├── common ├── mux │ ├── mux.go │ ├── frame_test.go │ └── session_test.go ├── peer │ ├── peer.go │ └── latency.go ├── protocol │ ├── udp │ │ ├── udp.go │ │ └── packet.go │ ├── protocol.go │ ├── payload.go │ ├── account.go │ ├── quic │ │ └── qtls_go118.go │ ├── id_test.go │ ├── time.go │ ├── context.go │ ├── server_spec.proto │ ├── headers.proto │ ├── time_test.go │ ├── user.proto │ ├── server_spec.go │ ├── id.go │ └── tls │ │ └── cert │ │ └── privateKey.go ├── buf │ ├── buf.go │ ├── readv_reader_wasm.go │ ├── readv_unix.go │ ├── readv_windows.go │ ├── override.go │ ├── readv_posix.go │ └── io_test.go ├── antireplay │ ├── antireplay.go │ └── bloomring.go ├── drain │ └── drain.go ├── singbridge │ └── error.go ├── task │ ├── common.go │ └── periodic_test.go ├── signal │ ├── notifier_test.go │ ├── pubsub │ │ └── pubsub_test.go │ ├── semaphore │ │ └── semaphore.go │ ├── notifier.go │ └── done │ │ └── done.go ├── cmdarg │ └── cmdarg.go ├── net │ ├── port_test.go │ ├── network.proto │ ├── destination.proto │ ├── network.go │ ├── address.proto │ ├── net.go │ └── port.proto ├── log │ ├── log.proto │ ├── log_test.go │ └── logger_test.go ├── bitmask │ ├── byte.go │ └── byte_test.go ├── crypto │ ├── crypto.go │ ├── chacha20.go │ ├── benchmark_test.go │ └── chunk_test.go ├── serial │ ├── typed_message.proto │ ├── typed_message_test.go │ ├── string.go │ ├── serial.go │ └── string_test.go ├── ctx │ └── context.go ├── strmatcher │ ├── full_matcher.go │ ├── full_matcher_test.go │ └── matchers.go ├── platform │ ├── windows.go │ ├── others.go │ └── filesystem │ │ └── file.go ├── xudp │ └── xudp_test.go ├── dice │ └── dice_test.go ├── type_test.go ├── errors │ └── multi_error.go ├── common_test.go └── type.go ├── infra └── conf │ ├── conf.go │ ├── serial │ └── serial.go │ ├── init.go │ ├── buildable.go │ ├── loopback.go │ ├── version.go │ ├── metrics.go │ ├── dns_proxy_test.go │ ├── blackhole_test.go │ ├── policy_test.go │ ├── http_test.go │ ├── cfgcommon │ └── duration │ │ ├── duration_test.go │ │ └── duration.go │ ├── lint.go │ ├── dokodemo_test.go │ ├── shadowsocks_test.go │ ├── reverse_test.go │ ├── general_test.go │ ├── freedom_test.go │ ├── dns_proxy.go │ └── dokodemo.go ├── proxy ├── http │ ├── http.go │ ├── config.go │ └── config.proto ├── freedom │ ├── config.go │ └── config.proto ├── trojan │ ├── trojan.go │ └── config.proto ├── loopback │ ├── config.go │ └── config.proto ├── vless │ ├── inbound │ │ ├── config.go │ │ └── config.proto │ ├── outbound │ │ ├── config.go │ │ └── config.proto │ ├── encoding │ │ └── addons.proto │ ├── vless.go │ └── account.proto ├── vmess │ ├── outbound │ │ ├── config.go │ │ ├── command.go │ │ └── config.proto │ ├── inbound │ │ ├── config.go │ │ └── config.proto │ ├── vmess.go │ ├── encoding │ │ └── encoding.go │ ├── aead │ │ ├── kdf.go │ │ └── consts.go │ ├── account.proto │ └── validator_test.go ├── shadowsocks_2022 │ ├── shadowsocks_2022.go │ └── config.go ├── socks │ ├── socks.go │ ├── config.go │ ├── udpfilter.go │ └── config.proto ├── shadowsocks │ ├── shadowsocks.go │ ├── config.proto │ └── config_test.go ├── dokodemo │ ├── fakeudp_other.go │ ├── config.go │ └── config.proto ├── wireguard │ ├── tun_default.go │ └── config.proto ├── blackhole │ ├── config.proto │ ├── config_test.go │ ├── blackhole_test.go │ └── config.go └── dns │ └── config.proto ├── app ├── proxyman │ ├── config.go │ ├── command │ │ └── doc.go │ └── outbound │ │ └── uot.go ├── dns │ ├── fakedns │ │ ├── fakedns.go │ │ └── fakedns.proto │ └── nameserver_local_test.go ├── dispatcher │ ├── dispatcher.go │ ├── config.proto │ ├── stats.go │ └── stats_test.go ├── observatory │ ├── observatory.go │ ├── burst │ │ ├── burst.go │ │ └── config.proto │ ├── explainErrors.go │ └── command │ │ └── command.proto ├── policy │ ├── policy.go │ ├── manager_test.go │ └── config.proto ├── app.go ├── reverse │ ├── config.go │ ├── portal_test.go │ └── config.proto ├── version │ └── config.proto ├── stats │ ├── config.proto │ ├── counter.go │ └── counter_test.go ├── metrics │ └── config.proto ├── log │ ├── command │ │ ├── config.proto │ │ └── command_test.go │ └── config.proto ├── commander │ ├── service.go │ └── config.proto └── router │ └── balancing_override.go ├── transport ├── internet │ ├── grpc │ │ ├── encoding │ │ │ ├── encoding.go │ │ │ └── stream.proto │ │ ├── grpc.go │ │ └── config.proto │ ├── tagged │ │ ├── taggedimpl │ │ │ └── taggedimpl.go │ │ └── tagged.go │ ├── tcp │ │ ├── tcp.go │ │ ├── config.go │ │ ├── sockopt_other.go │ │ ├── config.proto │ │ ├── sockopt_darwin.go │ │ ├── sockopt_freebsd.go │ │ └── sockopt_linux_test.go │ ├── udp │ │ ├── udp.go │ │ ├── config.go │ │ ├── config.proto │ │ ├── hub_other.go │ │ ├── dialer.go │ │ └── hub_linux.go │ ├── splithttp │ │ ├── splithttp.go │ │ ├── h1_conn.go │ │ ├── config_test.go │ │ ├── upload_queue_test.go │ │ ├── config.proto │ │ └── connection.go │ ├── httpupgrade │ │ ├── httpupgrade.go │ │ ├── connection.go │ │ ├── config.go │ │ └── config.proto │ ├── kcp │ │ ├── xor_amd64.go │ │ ├── kcp.go │ │ ├── cryptreal.go │ │ ├── xor.go │ │ ├── io_test.go │ │ ├── connection_test.go │ │ ├── xor_amd64.s │ │ ├── crypt_test.go │ │ └── output.go │ ├── tls │ │ ├── unsafe.go │ │ ├── config_windows.go │ │ ├── pin.go │ │ └── config_other.go │ ├── filelocker.go │ ├── filelocker_windows.go │ ├── websocket │ │ ├── ws.go │ │ ├── config.proto │ │ └── config.go │ ├── headers │ │ ├── http │ │ │ ├── linkedreadRequest.go │ │ │ └── resp.go │ │ ├── tls │ │ │ ├── config.proto │ │ │ └── dtls_test.go │ │ ├── wechat │ │ │ ├── config.proto │ │ │ ├── wechat_test.go │ │ │ └── wechat.go │ │ ├── utp │ │ │ ├── config.proto │ │ │ ├── utp_test.go │ │ │ └── utp.go │ │ ├── dns │ │ │ └── config.proto │ │ ├── wireguard │ │ │ ├── config.proto │ │ │ └── wireguard.go │ │ ├── noop │ │ │ ├── config.proto │ │ │ └── noop.go │ │ └── srtp │ │ │ ├── config.proto │ │ │ ├── srtp_test.go │ │ │ └── srtp.go │ ├── internet.go │ ├── sockopt.go │ ├── sockopt_other.go │ ├── stat │ │ └── connection.go │ ├── dialer_test.go │ ├── system_listener_test.go │ ├── sockopt_test.go │ ├── header.go │ ├── filelocker_other.go │ ├── sockopt_linux_test.go │ ├── reality │ │ └── config.proto │ └── header_test.go ├── link.go └── pipe │ ├── writer.go │ └── reader.go ├── features ├── extension │ ├── contextreceiver.go │ └── observatory.go ├── routing │ ├── balancer.go │ └── dispatcher.go ├── feature.go ├── dns │ └── fakedns.go └── policy │ └── default.go ├── main ├── distro │ └── debug │ │ └── debug.go ├── main_test.go ├── commands │ ├── base │ │ ├── root.go │ │ └── env.go │ └── all │ │ ├── convert │ │ └── convert.go │ │ ├── tls │ │ ├── tls.go │ │ └── certchainhash.go │ │ ├── commands.go │ │ ├── wg.go │ │ ├── api │ │ ├── api.go │ │ ├── outbounds_list.go │ │ ├── stats_sys.go │ │ └── logger_restart.go │ │ ├── x25519.go │ │ ├── uuid.go │ │ └── mldsa65.go ├── version.go └── confloader │ └── confloader.go ├── core ├── format.go ├── proto.go ├── context_test.go ├── annotations.go └── mocks.go ├── testing ├── scenarios │ ├── main_test.go │ ├── common_regular.go │ └── common_coverage.go ├── servers │ ├── tcp │ │ └── port.go │ ├── udp │ │ └── port.go │ └── http │ │ └── http.go └── coverage │ └── coverall2 ├── .github ├── ISSUE_TEMPLATE │ └── config.yml └── dependabot.yml └── .gitignore /common/mux/mux.go: -------------------------------------------------------------------------------- 1 | package mux 2 | -------------------------------------------------------------------------------- /common/peer/peer.go: -------------------------------------------------------------------------------- 1 | package peer 2 | -------------------------------------------------------------------------------- /infra/conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | -------------------------------------------------------------------------------- /proxy/http/http.go: -------------------------------------------------------------------------------- 1 | package http 2 | -------------------------------------------------------------------------------- /app/proxyman/config.go: -------------------------------------------------------------------------------- 1 | package proxyman 2 | -------------------------------------------------------------------------------- /common/protocol/udp/udp.go: -------------------------------------------------------------------------------- 1 | package udp 2 | -------------------------------------------------------------------------------- /proxy/freedom/config.go: -------------------------------------------------------------------------------- 1 | package freedom 2 | -------------------------------------------------------------------------------- /proxy/trojan/trojan.go: -------------------------------------------------------------------------------- 1 | package trojan 2 | -------------------------------------------------------------------------------- /app/dns/fakedns/fakedns.go: -------------------------------------------------------------------------------- 1 | package fakedns 2 | -------------------------------------------------------------------------------- /app/proxyman/command/doc.go: -------------------------------------------------------------------------------- 1 | package command 2 | -------------------------------------------------------------------------------- /infra/conf/serial/serial.go: -------------------------------------------------------------------------------- 1 | package serial 2 | -------------------------------------------------------------------------------- /proxy/loopback/config.go: -------------------------------------------------------------------------------- 1 | package loopback 2 | -------------------------------------------------------------------------------- /app/dispatcher/dispatcher.go: -------------------------------------------------------------------------------- 1 | package dispatcher 2 | -------------------------------------------------------------------------------- /proxy/vless/inbound/config.go: -------------------------------------------------------------------------------- 1 | package inbound 2 | -------------------------------------------------------------------------------- /proxy/vless/outbound/config.go: -------------------------------------------------------------------------------- 1 | package outbound 2 | -------------------------------------------------------------------------------- /proxy/vmess/outbound/config.go: -------------------------------------------------------------------------------- 1 | package outbound 2 | -------------------------------------------------------------------------------- /app/observatory/observatory.go: -------------------------------------------------------------------------------- 1 | package observatory 2 | -------------------------------------------------------------------------------- /transport/internet/grpc/encoding/encoding.go: -------------------------------------------------------------------------------- 1 | package encoding 2 | -------------------------------------------------------------------------------- /proxy/shadowsocks_2022/shadowsocks_2022.go: -------------------------------------------------------------------------------- 1 | package shadowsocks_2022 2 | -------------------------------------------------------------------------------- /transport/internet/tagged/taggedimpl/taggedimpl.go: -------------------------------------------------------------------------------- 1 | package taggedimpl 2 | -------------------------------------------------------------------------------- /transport/internet/tcp/tcp.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | const protocolName = "tcp" 4 | -------------------------------------------------------------------------------- /transport/internet/udp/udp.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | const protocolName = "udp" 4 | -------------------------------------------------------------------------------- /transport/internet/grpc/grpc.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | const protocolName = "grpc" 4 | -------------------------------------------------------------------------------- /transport/internet/splithttp/splithttp.go: -------------------------------------------------------------------------------- 1 | package splithttp 2 | 3 | const protocolName = "splithttp" 4 | -------------------------------------------------------------------------------- /app/policy/policy.go: -------------------------------------------------------------------------------- 1 | // Package policy is an implementation of policy.Manager feature. 2 | package policy 3 | -------------------------------------------------------------------------------- /proxy/socks/socks.go: -------------------------------------------------------------------------------- 1 | // Package socks provides implements of Socks protocol 4, 4a and 5. 2 | package socks 3 | -------------------------------------------------------------------------------- /transport/internet/httpupgrade/httpupgrade.go: -------------------------------------------------------------------------------- 1 | package httpupgrade 2 | 3 | const protocolName = "httpupgrade" 4 | -------------------------------------------------------------------------------- /app/app.go: -------------------------------------------------------------------------------- 1 | // Package app contains feature implementations of Xray. The features may be enabled during runtime. 2 | package app 3 | -------------------------------------------------------------------------------- /infra/conf/init.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | func init() { 4 | RegisterConfigureFilePostProcessingStage("FakeDNS", &FakeDNSPostProcessingStage{}) 5 | } 6 | -------------------------------------------------------------------------------- /transport/internet/kcp/xor_amd64.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | //go:noescape 4 | func xorfwd(x []byte) 5 | 6 | //go:noescape 7 | func xorbkd(x []byte) 8 | -------------------------------------------------------------------------------- /common/buf/buf.go: -------------------------------------------------------------------------------- 1 | // Package buf provides a light-weight memory allocation mechanism. 2 | package buf // import "github.com/xtls/xray-core/common/buf" 3 | -------------------------------------------------------------------------------- /common/antireplay/antireplay.go: -------------------------------------------------------------------------------- 1 | package antireplay 2 | 3 | type GeneralizedReplayFilter interface { 4 | Interval() int64 5 | Check(sum []byte) bool 6 | } 7 | -------------------------------------------------------------------------------- /common/drain/drain.go: -------------------------------------------------------------------------------- 1 | package drain 2 | 3 | import "io" 4 | 5 | type Drainer interface { 6 | AcknowledgeReceive(size int) 7 | Drain(reader io.Reader) error 8 | } 9 | -------------------------------------------------------------------------------- /features/extension/contextreceiver.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import "context" 4 | 5 | type ContextReceiver interface { 6 | InjectContext(ctx context.Context) 7 | } 8 | -------------------------------------------------------------------------------- /infra/conf/buildable.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import "google.golang.org/protobuf/proto" 4 | 5 | type Buildable interface { 6 | Build() (proto.Message, error) 7 | } 8 | -------------------------------------------------------------------------------- /transport/internet/tls/unsafe.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import _ "unsafe" 4 | 5 | //go:linkname errNoCertificates crypto/tls.errNoCertificates 6 | var errNoCertificates error 7 | -------------------------------------------------------------------------------- /main/distro/debug/debug.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func init() { 8 | go func() { 9 | http.ListenAndServe(":6060", nil) 10 | }() 11 | } 12 | -------------------------------------------------------------------------------- /transport/internet/filelocker.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | // FileLocker is UDS access lock 8 | type FileLocker struct { 9 | path string 10 | file *os.File 11 | } 12 | -------------------------------------------------------------------------------- /core/format.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | //go:generate go install -v github.com/daixiang0/gci@latest 4 | //go:generate go install -v mvdan.cc/gofumpt@latest 5 | //go:generate go run ../infra/vformat/main.go -pwd ./.. 6 | -------------------------------------------------------------------------------- /main/main_test.go: -------------------------------------------------------------------------------- 1 | //go:build coveragemain 2 | // +build coveragemain 3 | 4 | package main 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func TestRunMainForCoverage(t *testing.T) { 11 | main() 12 | } 13 | -------------------------------------------------------------------------------- /app/observatory/burst/burst.go: -------------------------------------------------------------------------------- 1 | package burst 2 | 3 | import ( 4 | "math" 5 | "time" 6 | ) 7 | 8 | const ( 9 | rttFailed = time.Duration(math.MaxInt64 - iota) 10 | rttUntested 11 | rttUnqualified 12 | ) 13 | -------------------------------------------------------------------------------- /testing/scenarios/main_test.go: -------------------------------------------------------------------------------- 1 | package scenarios 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestMain(m *testing.M) { 8 | genTestBinaryPath() 9 | defer testBinaryCleanFn() 10 | 11 | m.Run() 12 | } 13 | -------------------------------------------------------------------------------- /common/protocol/protocol.go: -------------------------------------------------------------------------------- 1 | package protocol // import "github.com/xtls/xray-core/common/protocol" 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ErrProtoNeedMoreData = errors.New("protocol matches, but need more data to complete sniffing") 8 | -------------------------------------------------------------------------------- /transport/internet/filelocker_windows.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | // Acquire lock 4 | func (fl *FileLocker) Acquire() error { 5 | return nil 6 | } 7 | 8 | // Release lock 9 | func (fl *FileLocker) Release() { 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /common/singbridge/error.go: -------------------------------------------------------------------------------- 1 | package singbridge 2 | 3 | import E "github.com/sagernet/sing/common/exceptions" 4 | 5 | func ReturnError(err error) error { 6 | if E.IsClosedOrCanceled(err) { 7 | return nil 8 | } 9 | return err 10 | } 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Community Support and Questions 3 | url: https://github.com/XTLS/Xray-core/discussions 4 | about: Please ask and answer questions there. The issue tracker is for issues with core. 5 | -------------------------------------------------------------------------------- /common/task/common.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import "github.com/xtls/xray-core/common" 4 | 5 | // Close returns a func() that closes v. 6 | func Close(v interface{}) func() error { 7 | return func() error { 8 | return common.Close(v) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/proto.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | //go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest 4 | //go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 5 | //go:generate go run ../infra/vprotogen/main.go -pwd ./.. 6 | -------------------------------------------------------------------------------- /proxy/shadowsocks/shadowsocks.go: -------------------------------------------------------------------------------- 1 | // Package shadowsocks provides compatible functionality to Shadowsocks. 2 | // 3 | // Shadowsocks client and server are implemented as outbound and inbound respectively in Xray's term. 4 | // 5 | // R.I.P Shadowsocks 6 | package shadowsocks 7 | -------------------------------------------------------------------------------- /transport/link.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import "github.com/xtls/xray-core/common/buf" 4 | 5 | // Link is a utility for connecting between an inbound and an outbound proxy handler. 6 | type Link struct { 7 | Reader buf.Reader 8 | Writer buf.Writer 9 | } 10 | -------------------------------------------------------------------------------- /proxy/vmess/inbound/config.go: -------------------------------------------------------------------------------- 1 | package inbound 2 | 3 | // GetDefaultValue returns default settings of DefaultConfig. 4 | func (c *Config) GetDefaultValue() *DefaultConfig { 5 | if c.GetDefault() == nil { 6 | return &DefaultConfig{} 7 | } 8 | return c.Default 9 | } 10 | -------------------------------------------------------------------------------- /transport/internet/kcp/kcp.go: -------------------------------------------------------------------------------- 1 | // Package kcp - A Fast and Reliable ARQ Protocol 2 | // 3 | // Acknowledgement: 4 | // 5 | // skywind3000@github for inventing the KCP protocol 6 | // xtaci@github for translating to Golang 7 | package kcp 8 | 9 | const protocolName = "mkcp" 10 | -------------------------------------------------------------------------------- /transport/internet/websocket/ws.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package websocket implements WebSocket transport 3 | 4 | WebSocket transport implements an HTTP(S) compliable, surveillance proof transport method with plausible deniability. 5 | */ 6 | package websocket 7 | 8 | const protocolName = "websocket" 9 | -------------------------------------------------------------------------------- /common/buf/readv_reader_wasm.go: -------------------------------------------------------------------------------- 1 | //go:build wasm 2 | // +build wasm 3 | 4 | package buf 5 | 6 | import ( 7 | "io" 8 | "syscall" 9 | ) 10 | 11 | const useReadv = false 12 | 13 | func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) Reader { 14 | panic("not implemented") 15 | } 16 | -------------------------------------------------------------------------------- /proxy/dokodemo/fakeudp_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | package dokodemo 5 | 6 | import ( 7 | "fmt" 8 | "net" 9 | ) 10 | 11 | func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) { 12 | return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("!linux")} 13 | } 14 | -------------------------------------------------------------------------------- /transport/internet/headers/http/linkedreadRequest.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "bufio" 5 | "net/http" 6 | // required to use go:linkname 7 | _ "unsafe" 8 | ) 9 | 10 | //go:linkname readRequest net/http.readRequest 11 | func readRequest(b *bufio.Reader) (req *http.Request, err error) 12 | -------------------------------------------------------------------------------- /features/routing/balancer.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | type BalancerOverrider interface { 4 | SetOverrideTarget(tag, target string) error 5 | GetOverrideTarget(tag string) (string, error) 6 | } 7 | 8 | type BalancerPrincipleTarget interface { 9 | GetPrincipleTarget(tag string) ([]string, error) 10 | } 11 | -------------------------------------------------------------------------------- /transport/internet/tls/config_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package tls 5 | 6 | import "crypto/x509" 7 | 8 | func (c *Config) getCertPool() (*x509.CertPool, error) { 9 | if c.DisableSystemRoot { 10 | return c.loadSelfCertPool() 11 | } 12 | 13 | return nil, nil 14 | } 15 | -------------------------------------------------------------------------------- /transport/internet/tcp/config.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/transport/internet" 6 | ) 7 | 8 | func init() { 9 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 10 | return new(Config) 11 | })) 12 | } 13 | -------------------------------------------------------------------------------- /transport/internet/udp/config.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/transport/internet" 6 | ) 7 | 8 | func init() { 9 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 10 | return new(Config) 11 | })) 12 | } 13 | -------------------------------------------------------------------------------- /app/reverse/config.go: -------------------------------------------------------------------------------- 1 | package reverse 2 | 3 | import ( 4 | "crypto/rand" 5 | "io" 6 | 7 | "github.com/xtls/xray-core/common/dice" 8 | ) 9 | 10 | func (c *Control) FillInRandom() { 11 | randomLength := dice.Roll(64) 12 | randomLength++ 13 | c.Random = make([]byte, randomLength) 14 | io.ReadFull(rand.Reader, c.Random) 15 | } 16 | -------------------------------------------------------------------------------- /transport/internet/kcp/cryptreal.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "crypto/cipher" 5 | "crypto/sha256" 6 | 7 | "github.com/xtls/xray-core/common/crypto" 8 | ) 9 | 10 | func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD { 11 | hashedSeed := sha256.Sum256([]byte(seed)) 12 | return crypto.NewAesGcm(hashedSeed[:16]) 13 | } 14 | -------------------------------------------------------------------------------- /common/signal/notifier_test.go: -------------------------------------------------------------------------------- 1 | package signal_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/signal" 7 | ) 8 | 9 | func TestNotifierSignal(t *testing.T) { 10 | n := NewNotifier() 11 | 12 | w := n.Wait() 13 | n.Signal() 14 | 15 | select { 16 | case <-w: 17 | default: 18 | t.Fail() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /transport/internet/tagged/tagged.go: -------------------------------------------------------------------------------- 1 | package tagged 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | "github.com/xtls/xray-core/features/routing" 8 | ) 9 | 10 | type DialFunc func(ctx context.Context, dispatcher routing.Dispatcher, dest net.Destination, tag string) (net.Conn, error) 11 | 12 | var Dialer DialFunc 13 | -------------------------------------------------------------------------------- /common/protocol/payload.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | type TransferType byte 4 | 5 | const ( 6 | TransferTypeStream TransferType = 0 7 | TransferTypePacket TransferType = 1 8 | ) 9 | 10 | type AddressType byte 11 | 12 | const ( 13 | AddressTypeIPv4 AddressType = 1 14 | AddressTypeDomain AddressType = 2 15 | AddressTypeIPv6 AddressType = 3 16 | ) 17 | -------------------------------------------------------------------------------- /common/protocol/udp/packet.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/buf" 5 | "github.com/xtls/xray-core/common/net" 6 | ) 7 | 8 | // Packet is a UDP packet together with its source and destination address. 9 | type Packet struct { 10 | Payload *buf.Buffer 11 | Source net.Destination 12 | Target net.Destination 13 | } 14 | -------------------------------------------------------------------------------- /proxy/vmess/outbound/command.go: -------------------------------------------------------------------------------- 1 | package outbound 2 | 3 | import ( 4 | 5 | "github.com/xtls/xray-core/common/net" 6 | "github.com/xtls/xray-core/common/protocol" 7 | ) 8 | 9 | // As a stub command consumer. 10 | func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) { 11 | switch cmd.(type) { 12 | default: 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /proxy/loopback/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.loopback; 4 | option csharp_namespace = "Xray.Proxy.Loopback"; 5 | option go_package = "github.com/xtls/xray-core/proxy/loopback"; 6 | option java_package = "com.xray.proxy.loopback"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | string inbound_tag = 1; 11 | } 12 | -------------------------------------------------------------------------------- /proxy/vmess/vmess.go: -------------------------------------------------------------------------------- 1 | // Package vmess contains the implementation of VMess protocol and transportation. 2 | // 3 | // VMess contains both inbound and outbound connections. VMess inbound is usually used on servers 4 | // together with 'freedom' to talk to final destination, while VMess outbound is usually used on 5 | // clients with 'socks' for proxying. 6 | package vmess 7 | -------------------------------------------------------------------------------- /transport/internet/udp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.udp; 4 | option csharp_namespace = "Xray.Transport.Internet.Udp"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/udp"; 6 | option java_package = "com.xray.transport.internet.udp"; 7 | option java_multiple_files = true; 8 | 9 | message Config {} 10 | -------------------------------------------------------------------------------- /transport/internet/internet.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | import ( 4 | "net" 5 | "strings" 6 | ) 7 | 8 | func IsValidHTTPHost(request string, config string) bool { 9 | r := strings.ToLower(request) 10 | c := strings.ToLower(config) 11 | if strings.Contains(r, ":") { 12 | h, _, _ := net.SplitHostPort(r) 13 | return h == c 14 | } 15 | return r == c 16 | } 17 | -------------------------------------------------------------------------------- /infra/conf/loopback.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/xtls/xray-core/proxy/loopback" 5 | "google.golang.org/protobuf/proto" 6 | ) 7 | 8 | type LoopbackConfig struct { 9 | InboundTag string `json:"inboundTag"` 10 | } 11 | 12 | func (l LoopbackConfig) Build() (proto.Message, error) { 13 | return &loopback.Config{InboundTag: l.InboundTag}, nil 14 | } 15 | -------------------------------------------------------------------------------- /common/cmdarg/cmdarg.go: -------------------------------------------------------------------------------- 1 | package cmdarg 2 | 3 | import "strings" 4 | 5 | // Arg is used by flag to accept multiple argument. 6 | type Arg []string 7 | 8 | func (c *Arg) String() string { 9 | return strings.Join([]string(*c), " ") 10 | } 11 | 12 | // Set is the method flag package calls 13 | func (c *Arg) Set(value string) error { 14 | *c = append(*c, value) 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /common/net/port_test.go: -------------------------------------------------------------------------------- 1 | package net_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/net" 7 | ) 8 | 9 | func TestPortRangeContains(t *testing.T) { 10 | portRange := &PortRange{ 11 | From: 53, 12 | To: 53, 13 | } 14 | 15 | if !portRange.Contains(Port(53)) { 16 | t.Error("expected port range containing 53, but actually not") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/context_test.go: -------------------------------------------------------------------------------- 1 | package core_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | _ "unsafe" 7 | 8 | . "github.com/xtls/xray-core/core" 9 | ) 10 | 11 | func TestFromContextPanic(t *testing.T) { 12 | defer func() { 13 | r := recover() 14 | if r == nil { 15 | t.Error("expect panic, but nil") 16 | } 17 | }() 18 | 19 | MustFromContext(context.Background()) 20 | } 21 | -------------------------------------------------------------------------------- /proxy/dokodemo/config.go: -------------------------------------------------------------------------------- 1 | package dokodemo 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/net" 5 | ) 6 | 7 | // GetPredefinedAddress returns the defined address from proto config. Null if address is not valid. 8 | func (v *Config) GetPredefinedAddress() net.Address { 9 | addr := v.Address.AsAddress() 10 | if addr == nil { 11 | return nil 12 | } 13 | return addr 14 | } 15 | -------------------------------------------------------------------------------- /common/protocol/account.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import "google.golang.org/protobuf/proto" 4 | 5 | // Account is a user identity used for authentication. 6 | type Account interface { 7 | Equals(Account) bool 8 | ToProto() proto.Message 9 | } 10 | 11 | // AsAccount is an object can be converted into account. 12 | type AsAccount interface { 13 | AsAccount() (Account, error) 14 | } 15 | -------------------------------------------------------------------------------- /transport/internet/splithttp/h1_conn.go: -------------------------------------------------------------------------------- 1 | package splithttp 2 | 3 | import ( 4 | "bufio" 5 | "net" 6 | ) 7 | 8 | type H1Conn struct { 9 | UnreadedResponsesCount int 10 | RespBufReader *bufio.Reader 11 | net.Conn 12 | } 13 | 14 | func NewH1Conn(conn net.Conn) *H1Conn { 15 | return &H1Conn{ 16 | RespBufReader: bufio.NewReader(conn), 17 | Conn: conn, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /common/log/log.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.log; 4 | option csharp_namespace = "Xray.Common.Log"; 5 | option go_package = "github.com/xtls/xray-core/common/log"; 6 | option java_package = "com.xray.common.log"; 7 | option java_multiple_files = true; 8 | 9 | enum Severity { 10 | Unknown = 0; 11 | Error = 1; 12 | Warning = 2; 13 | Info = 3; 14 | Debug = 4; 15 | } 16 | -------------------------------------------------------------------------------- /transport/internet/splithttp/config_test.go: -------------------------------------------------------------------------------- 1 | package splithttp_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/transport/internet/splithttp" 7 | ) 8 | 9 | func Test_GetNormalizedPath(t *testing.T) { 10 | c := Config{ 11 | Path: "/?world", 12 | } 13 | 14 | path := c.GetNormalizedPath() 15 | if path != "/" { 16 | t.Error("Unexpected: ", path) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /transport/internet/tcp/sockopt_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !freebsd && !darwin 2 | // +build !linux,!freebsd,!darwin 3 | 4 | package tcp 5 | 6 | import ( 7 | "github.com/xtls/xray-core/common/net" 8 | "github.com/xtls/xray-core/transport/internet/stat" 9 | ) 10 | 11 | func GetOriginalDestination(conn stat.Connection) (net.Destination, error) { 12 | return net.Destination{}, nil 13 | } 14 | -------------------------------------------------------------------------------- /features/feature.go: -------------------------------------------------------------------------------- 1 | package features 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | ) 6 | 7 | // Feature is the interface for Xray features. All features must implement this interface. 8 | // All existing features have an implementation in app directory. These features can be replaced by third-party ones. 9 | type Feature interface { 10 | common.HasType 11 | common.Runnable 12 | } 13 | -------------------------------------------------------------------------------- /features/extension/observatory.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/xtls/xray-core/features" 7 | "google.golang.org/protobuf/proto" 8 | ) 9 | 10 | type Observatory interface { 11 | features.Feature 12 | 13 | GetObservation(ctx context.Context) (proto.Message, error) 14 | } 15 | 16 | func ObservatoryType() interface{} { 17 | return (*Observatory)(nil) 18 | } 19 | -------------------------------------------------------------------------------- /proxy/vless/encoding/addons.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vless.encoding; 4 | option csharp_namespace = "Xray.Proxy.Vless.Encoding"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vless/encoding"; 6 | option java_package = "com.xray.proxy.vless.encoding"; 7 | option java_multiple_files = true; 8 | 9 | message Addons { 10 | string Flow = 1; 11 | bytes Seed = 2; 12 | } 13 | -------------------------------------------------------------------------------- /proxy/wireguard/tun_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux || android 2 | 3 | package wireguard 4 | 5 | import ( 6 | "errors" 7 | "net/netip" 8 | ) 9 | 10 | func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousModeHandler) (t Tunnel, err error) { 11 | return nil, errors.New("not implemented") 12 | } 13 | 14 | func KernelTunSupported() (bool, error) { 15 | return false, nil 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/headers/tls/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.tls; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.Tls"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/tls"; 6 | option java_package = "com.xray.transport.internet.headers.tls"; 7 | option java_multiple_files = true; 8 | 9 | message PacketConfig {} 10 | -------------------------------------------------------------------------------- /app/version/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.version; 4 | option csharp_namespace = "Xray.App.Version"; 5 | option go_package = "github.com/xtls/xray-core/app/version"; 6 | option java_package = "com.xray.app.version"; 7 | option java_multiple_files = true; 8 | 9 | 10 | message Config { 11 | string core_version = 1; 12 | string min_version = 2; 13 | string max_version = 3; 14 | } 15 | -------------------------------------------------------------------------------- /transport/internet/headers/wechat/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.wechat; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.Wechat"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/wechat"; 6 | option java_package = "com.xray.transport.internet.headers.wechat"; 7 | option java_multiple_files = true; 8 | 9 | message VideoConfig {} 10 | -------------------------------------------------------------------------------- /app/dispatcher/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.dispatcher; 4 | option csharp_namespace = "Xray.App.Dispatcher"; 5 | option go_package = "github.com/xtls/xray-core/app/dispatcher"; 6 | option java_package = "com.xray.app.dispatcher"; 7 | option java_multiple_files = true; 8 | 9 | message SessionConfig { 10 | reserved 1; 11 | } 12 | 13 | message Config { 14 | SessionConfig settings = 1; 15 | } 16 | -------------------------------------------------------------------------------- /app/stats/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.stats; 4 | option csharp_namespace = "Xray.App.Stats"; 5 | option go_package = "github.com/xtls/xray-core/app/stats"; 6 | option java_package = "com.xray.app.stats"; 7 | option java_multiple_files = true; 8 | 9 | message Config {} 10 | 11 | message ChannelConfig { 12 | bool Blocking = 1; 13 | int32 SubscriberLimit = 2; 14 | int32 BufferSize = 3; 15 | } 16 | -------------------------------------------------------------------------------- /common/bitmask/byte.go: -------------------------------------------------------------------------------- 1 | package bitmask 2 | 3 | // Byte is a bitmask in byte. 4 | type Byte byte 5 | 6 | // Has returns true if this bitmask contains another bitmask. 7 | func (b Byte) Has(bb Byte) bool { 8 | return (b & bb) != 0 9 | } 10 | 11 | func (b *Byte) Set(bb Byte) { 12 | *b |= bb 13 | } 14 | 15 | func (b *Byte) Clear(bb Byte) { 16 | *b &= ^bb 17 | } 18 | 19 | func (b *Byte) Toggle(bb Byte) { 20 | *b ^= bb 21 | } 22 | -------------------------------------------------------------------------------- /transport/internet/httpupgrade/connection.go: -------------------------------------------------------------------------------- 1 | package httpupgrade 2 | 3 | import "net" 4 | 5 | type connection struct { 6 | net.Conn 7 | remoteAddr net.Addr 8 | } 9 | 10 | func newConnection(conn net.Conn, remoteAddr net.Addr) *connection { 11 | return &connection{ 12 | Conn: conn, 13 | remoteAddr: remoteAddr, 14 | } 15 | } 16 | 17 | func (c *connection) RemoteAddr() net.Addr { 18 | return c.remoteAddr 19 | } 20 | -------------------------------------------------------------------------------- /common/protocol/quic/qtls_go118.go: -------------------------------------------------------------------------------- 1 | package quic 2 | 3 | import ( 4 | "crypto" 5 | "crypto/cipher" 6 | _ "crypto/tls" 7 | _ "unsafe" 8 | ) 9 | 10 | type CipherSuiteTLS13 struct { 11 | ID uint16 12 | KeyLen int 13 | AEAD func(key, fixedNonce []byte) cipher.AEAD 14 | Hash crypto.Hash 15 | } 16 | 17 | //go:linkname AEADAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 18 | func AEADAESGCMTLS13(key, nonceMask []byte) cipher.AEAD 19 | -------------------------------------------------------------------------------- /transport/internet/headers/utp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.utp; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.Utp"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/utp"; 6 | option java_package = "com.xray.transport.internet.headers.utp"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | uint32 version = 1; 11 | } 12 | -------------------------------------------------------------------------------- /main/commands/base/root.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | // RootCommand is the root command of all commands 4 | var RootCommand *Command 5 | 6 | func init() { 7 | RootCommand = &Command{ 8 | UsageLine: CommandEnv.Exec, 9 | Long: "The root command", 10 | } 11 | } 12 | 13 | // RegisterCommand register a command to RootCommand 14 | func RegisterCommand(cmd *Command) { 15 | RootCommand.Commands = append(RootCommand.Commands, cmd) 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/headers/dns/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.dns; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.DNS"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/dns"; 6 | option java_package = "com.xray.transport.internet.headers.dns"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | string domain = 1; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /transport/internet/headers/wireguard/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.wireguard; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.Wireguard"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/wireguard"; 6 | option java_package = "com.xray.transport.internet.headers.wireguard"; 7 | option java_multiple_files = true; 8 | 9 | message WireguardConfig {} 10 | -------------------------------------------------------------------------------- /main/commands/all/convert/convert.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "github.com/xtls/xray-core/main/commands/base" 5 | ) 6 | 7 | // CmdConvert do config convertion 8 | var CmdConvert = &base.Command{ 9 | UsageLine: "{{.Exec}} convert", 10 | Short: "Convert configs", 11 | Long: `{{.Exec}} {{.LongName}} provides tools to convert config. 12 | `, 13 | Commands: []*base.Command{ 14 | cmdProtobuf, 15 | cmdJson, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /main/commands/all/tls/tls.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import ( 4 | "github.com/xtls/xray-core/main/commands/base" 5 | ) 6 | 7 | // CmdTLS holds all tls sub commands 8 | var CmdTLS = &base.Command{ 9 | UsageLine: "{{.Exec}} tls", 10 | Short: "TLS tools", 11 | Long: `{{.Exec}} {{.LongName}} provides tools for TLS. 12 | `, 13 | Commands: []*base.Command{ 14 | cmdCert, 15 | cmdPing, 16 | cmdCertChainHash, 17 | cmdECH, 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /proxy/vless/vless.go: -------------------------------------------------------------------------------- 1 | // Package vless contains the implementation of VLess protocol and transportation. 2 | // 3 | // VLess contains both inbound and outbound connections. VLess inbound is usually used on servers 4 | // together with 'freedom' to talk to final destination, while VLess outbound is usually used on 5 | // clients with 'socks' for proxying. 6 | package vless 7 | 8 | const ( 9 | None = "none" 10 | XRV = "xtls-rprx-vision" 11 | ) 12 | -------------------------------------------------------------------------------- /transport/internet/headers/noop/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.noop; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.Noop"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/noop"; 6 | option java_package = "com.xray.transport.internet.headers.noop"; 7 | option java_multiple_files = true; 8 | 9 | message Config {} 10 | 11 | message ConnectionConfig {} 12 | -------------------------------------------------------------------------------- /transport/internet/kcp/xor.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 2 | // +build !amd64 3 | 4 | package kcp 5 | 6 | // xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len 7 | func xorfwd(x []byte) { 8 | for i := 4; i < len(x); i++ { 9 | x[i] ^= x[i-4] 10 | } 11 | } 12 | 13 | // xorbkd performs XOR backwords in words, x[i] ^= x[i-4], i from len to 0 14 | func xorbkd(x []byte) { 15 | for i := len(x) - 1; i >= 4; i-- { 16 | x[i] ^= x[i-4] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /proxy/vless/outbound/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vless.outbound; 4 | option csharp_namespace = "Xray.Proxy.Vless.Outbound"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vless/outbound"; 6 | option java_package = "com.xray.proxy.vless.outbound"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | 11 | message Config { 12 | xray.common.protocol.ServerEndpoint vnext = 1; 13 | } 14 | -------------------------------------------------------------------------------- /proxy/vmess/outbound/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vmess.outbound; 4 | option csharp_namespace = "Xray.Proxy.Vmess.Outbound"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vmess/outbound"; 6 | option java_package = "com.xray.proxy.vmess.outbound"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | 11 | message Config { 12 | xray.common.protocol.ServerEndpoint Receiver = 1; 13 | } 14 | -------------------------------------------------------------------------------- /common/crypto/crypto.go: -------------------------------------------------------------------------------- 1 | // Package crypto provides common crypto libraries for Xray. 2 | package crypto // import "github.com/xtls/xray-core/common/crypto" 3 | 4 | import ( 5 | "crypto/rand" 6 | "math/big" 7 | ) 8 | 9 | func RandBetween(from int64, to int64) int64 { 10 | if from == to { 11 | return from 12 | } 13 | if from > to { 14 | from, to = to, from 15 | } 16 | bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from)) 17 | return from + bigInt.Int64() 18 | } 19 | -------------------------------------------------------------------------------- /common/crypto/chacha20.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/cipher" 5 | 6 | "github.com/xtls/xray-core/common/crypto/internal" 7 | ) 8 | 9 | // NewChaCha20Stream creates a new Chacha20 encryption/descryption stream based on give key and IV. 10 | // Caller must ensure the length of key is 32 bytes, and length of IV is either 8 or 12 bytes. 11 | func NewChaCha20Stream(key []byte, iv []byte) cipher.Stream { 12 | return internal.NewChaCha20Stream(key, iv, 20) 13 | } 14 | -------------------------------------------------------------------------------- /app/metrics/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.metrics; 4 | option csharp_namespace = "Xray.App.Metrics"; 5 | option go_package = "github.com/xtls/xray-core/app/metrics"; 6 | option java_package = "com.xray.app.metrics"; 7 | option java_multiple_files = true; 8 | 9 | // Config is the settings for metrics. 10 | message Config { 11 | // Tag of the outbound handler that handles metrics http connections. 12 | string tag = 1; 13 | string listen = 2; 14 | } 15 | -------------------------------------------------------------------------------- /transport/internet/grpc/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.grpc.encoding; 4 | option go_package = "github.com/xtls/xray-core/transport/internet/grpc"; 5 | 6 | message Config { 7 | string authority = 1; 8 | string service_name = 2; 9 | bool multi_mode = 3; 10 | int32 idle_timeout = 4; 11 | int32 health_check_timeout = 5; 12 | bool permit_without_stream = 6; 13 | int32 initial_windows_size = 7; 14 | string user_agent = 8; 15 | } 16 | -------------------------------------------------------------------------------- /transport/internet/grpc/encoding/stream.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.grpc.encoding; 4 | option go_package = "github.com/xtls/xray-core/transport/internet/grpc/encoding"; 5 | 6 | message Hunk { 7 | bytes data = 1; 8 | } 9 | 10 | message MultiHunk { 11 | repeated bytes data = 1; 12 | } 13 | 14 | service GRPCService { 15 | rpc Tun (stream Hunk) returns (stream Hunk); 16 | rpc TunMulti (stream MultiHunk) returns (stream MultiHunk); 17 | } 18 | -------------------------------------------------------------------------------- /common/net/network.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.net; 4 | option csharp_namespace = "Xray.Common.Net"; 5 | option go_package = "github.com/xtls/xray-core/common/net"; 6 | option java_package = "com.xray.common.net"; 7 | option java_multiple_files = true; 8 | 9 | enum Network { 10 | Unknown = 0; 11 | 12 | TCP = 2; 13 | UDP = 3; 14 | UNIX = 4; 15 | } 16 | 17 | // NetworkList is a list of Networks. 18 | message NetworkList { repeated Network network = 1; } 19 | -------------------------------------------------------------------------------- /app/reverse/portal_test.go: -------------------------------------------------------------------------------- 1 | package reverse_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/app/reverse" 7 | "github.com/xtls/xray-core/common" 8 | ) 9 | 10 | func TestStaticPickerEmpty(t *testing.T) { 11 | picker, err := reverse.NewStaticMuxPicker() 12 | common.Must(err) 13 | worker, err := picker.PickAvailable() 14 | if err == nil { 15 | t.Error("expected error, but nil") 16 | } 17 | if worker != nil { 18 | t.Error("expected nil worker, but not nil") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /common/protocol/id_test.go: -------------------------------------------------------------------------------- 1 | package protocol_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/protocol" 7 | "github.com/xtls/xray-core/common/uuid" 8 | ) 9 | 10 | func TestIdEquals(t *testing.T) { 11 | id1 := NewID(uuid.New()) 12 | id2 := NewID(id1.UUID()) 13 | 14 | if !id1.Equals(id2) { 15 | t.Error("expected id1 to equal id2, but actually not") 16 | } 17 | 18 | if id1.String() != id2.String() { 19 | t.Error(id1.String(), " != ", id2.String()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /proxy/blackhole/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.blackhole; 4 | option csharp_namespace = "Xray.Proxy.Blackhole"; 5 | option go_package = "github.com/xtls/xray-core/proxy/blackhole"; 6 | option java_package = "com.xray.proxy.blackhole"; 7 | option java_multiple_files = true; 8 | 9 | import "common/serial/typed_message.proto"; 10 | 11 | message NoneResponse {} 12 | 13 | message HTTPResponse {} 14 | 15 | message Config { 16 | xray.common.serial.TypedMessage response = 1; 17 | } 18 | -------------------------------------------------------------------------------- /testing/servers/tcp/port.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/common/net" 6 | ) 7 | 8 | // PickPort returns an unused TCP port in the system. The port returned is highly likely to be unused, but not guaranteed. 9 | func PickPort() net.Port { 10 | listener, err := net.Listen("tcp4", "127.0.0.1:0") 11 | common.Must(err) 12 | defer listener.Close() 13 | 14 | addr := listener.Addr().(*net.TCPAddr) 15 | return net.Port(addr.Port) 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/udp/hub_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !freebsd && !darwin 2 | // +build !linux,!freebsd,!darwin 3 | 4 | package udp 5 | 6 | import ( 7 | "github.com/xtls/xray-core/common/net" 8 | ) 9 | 10 | func RetrieveOriginalDest(oob []byte) net.Destination { 11 | return net.Destination{} 12 | } 13 | 14 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) { 15 | nBytes, addr, err := conn.ReadFromUDP(payload) 16 | return nBytes, 0, 0, addr, err 17 | } 18 | -------------------------------------------------------------------------------- /common/protocol/time.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/xtls/xray-core/common/dice" 7 | ) 8 | 9 | type Timestamp int64 10 | 11 | type TimestampGenerator func() Timestamp 12 | 13 | func NowTime() Timestamp { 14 | return Timestamp(time.Now().Unix()) 15 | } 16 | 17 | func NewTimestampGenerator(base Timestamp, delta int) TimestampGenerator { 18 | return func() Timestamp { 19 | rangeInDelta := dice.Roll(delta*2) - delta 20 | return base + Timestamp(rangeInDelta) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /transport/internet/splithttp/upload_queue_test.go: -------------------------------------------------------------------------------- 1 | package splithttp_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common" 7 | . "github.com/xtls/xray-core/transport/internet/splithttp" 8 | ) 9 | 10 | func Test_regression_readzero(t *testing.T) { 11 | q := NewUploadQueue(10) 12 | q.Push(Packet{ 13 | Payload: []byte("x"), 14 | Seq: 0, 15 | }) 16 | buf := make([]byte, 20) 17 | n, err := q.Read(buf) 18 | common.Must(err) 19 | if n != 1 { 20 | t.Error("n=", n) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/net/destination.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.net; 4 | option csharp_namespace = "Xray.Common.Net"; 5 | option go_package = "github.com/xtls/xray-core/common/net"; 6 | option java_package = "com.xray.common.net"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/network.proto"; 10 | import "common/net/address.proto"; 11 | 12 | // Endpoint of a network connection. 13 | message Endpoint { 14 | Network network = 1; 15 | IPOrDomain address = 2; 16 | uint32 port = 3; 17 | } 18 | -------------------------------------------------------------------------------- /common/protocol/context.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type key int 8 | 9 | const ( 10 | requestKey key = iota 11 | ) 12 | 13 | func ContextWithRequestHeader(ctx context.Context, request *RequestHeader) context.Context { 14 | return context.WithValue(ctx, requestKey, request) 15 | } 16 | 17 | func RequestHeaderFromContext(ctx context.Context) *RequestHeader { 18 | request := ctx.Value(requestKey) 19 | if request == nil { 20 | return nil 21 | } 22 | return request.(*RequestHeader) 23 | } 24 | -------------------------------------------------------------------------------- /app/log/command/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.log.command; 4 | option csharp_namespace = "Xray.App.Log.Command"; 5 | option go_package = "github.com/xtls/xray-core/app/log/command"; 6 | option java_package = "com.xray.app.log.command"; 7 | option java_multiple_files = true; 8 | 9 | message Config {} 10 | 11 | message RestartLoggerRequest {} 12 | 13 | message RestartLoggerResponse {} 14 | 15 | service LoggerService { 16 | rpc RestartLogger(RestartLoggerRequest) returns (RestartLoggerResponse) {} 17 | } 18 | -------------------------------------------------------------------------------- /transport/internet/httpupgrade/config.go: -------------------------------------------------------------------------------- 1 | package httpupgrade 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/transport/internet" 6 | ) 7 | 8 | func (c *Config) GetNormalizedPath() string { 9 | path := c.Path 10 | if path == "" { 11 | return "/" 12 | } 13 | if path[0] != '/' { 14 | return "/" + path 15 | } 16 | return path 17 | } 18 | 19 | func init() { 20 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 21 | return new(Config) 22 | })) 23 | } 24 | -------------------------------------------------------------------------------- /transport/internet/tcp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.tcp; 4 | option csharp_namespace = "Xray.Transport.Internet.Tcp"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/tcp"; 6 | option java_package = "com.xray.transport.internet.tcp"; 7 | option java_multiple_files = true; 8 | 9 | import "common/serial/typed_message.proto"; 10 | 11 | message Config { 12 | reserved 1; 13 | xray.common.serial.TypedMessage header_settings = 2; 14 | bool accept_proxy_protocol = 3; 15 | } 16 | -------------------------------------------------------------------------------- /common/net/network.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | func (n Network) SystemString() string { 4 | switch n { 5 | case Network_TCP: 6 | return "tcp" 7 | case Network_UDP: 8 | return "udp" 9 | case Network_UNIX: 10 | return "unix" 11 | default: 12 | return "unknown" 13 | } 14 | } 15 | 16 | // HasNetwork returns true if the network list has a certain network. 17 | func HasNetwork(list []Network, network Network) bool { 18 | for _, value := range list { 19 | if value == network { 20 | return true 21 | } 22 | } 23 | return false 24 | } 25 | -------------------------------------------------------------------------------- /common/protocol/server_spec.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.protocol; 4 | option csharp_namespace = "Xray.Common.Protocol"; 5 | option go_package = "github.com/xtls/xray-core/common/protocol"; 6 | option java_package = "com.xray.common.protocol"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/address.proto"; 10 | import "common/protocol/user.proto"; 11 | 12 | message ServerEndpoint { 13 | xray.common.net.IPOrDomain address = 1; 14 | uint32 port = 2; 15 | xray.common.protocol.User user = 3; 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/httpupgrade/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.httpupgrade; 4 | option csharp_namespace = "Xray.Transport.Internet.HttpUpgrade"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/httpupgrade"; 6 | option java_package = "com.xray.transport.internet.httpupgrade"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | string host = 1; 11 | string path = 2; 12 | map header = 3; 13 | bool accept_proxy_protocol = 4; 14 | uint32 ed = 5; 15 | } 16 | -------------------------------------------------------------------------------- /common/protocol/headers.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.protocol; 4 | option csharp_namespace = "Xray.Common.Protocol"; 5 | option go_package = "github.com/xtls/xray-core/common/protocol"; 6 | option java_package = "com.xray.common.protocol"; 7 | option java_multiple_files = true; 8 | 9 | enum SecurityType { 10 | UNKNOWN = 0; 11 | AUTO = 2; 12 | AES128_GCM = 3; 13 | CHACHA20_POLY1305 = 4; 14 | NONE = 5; // [DEPRECATED 2023-06] 15 | ZERO = 6; 16 | } 17 | 18 | message SecurityConfig { 19 | SecurityType type = 1; 20 | } 21 | -------------------------------------------------------------------------------- /common/serial/typed_message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.serial; 4 | option csharp_namespace = "Xray.Common.Serial"; 5 | option go_package = "github.com/xtls/xray-core/common/serial"; 6 | option java_package = "com.xray.common.serial"; 7 | option java_multiple_files = true; 8 | 9 | // TypedMessage is a serialized proto message along with its type name. 10 | message TypedMessage { 11 | // The name of the message type, retrieved from protobuf API. 12 | string type = 1; 13 | // Serialized proto message. 14 | bytes value = 2; 15 | } 16 | -------------------------------------------------------------------------------- /common/serial/typed_message_test.go: -------------------------------------------------------------------------------- 1 | package serial_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/serial" 7 | ) 8 | 9 | func TestGetInstance(t *testing.T) { 10 | p, err := GetInstance("") 11 | if p != nil { 12 | t.Error("expected nil instance, but got ", p) 13 | } 14 | if err == nil { 15 | t.Error("expect non-nil error, but got nil") 16 | } 17 | } 18 | 19 | func TestConvertingNilMessage(t *testing.T) { 20 | x := ToTypedMessage(nil) 21 | if x != nil { 22 | t.Error("expect nil, but actually not") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/servers/udp/port.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/common/net" 6 | ) 7 | 8 | // PickPort returns an unused UDP port in the system. The port returned is highly likely to be unused, but not guaranteed. 9 | func PickPort() net.Port { 10 | conn, err := net.ListenUDP("udp4", &net.UDPAddr{ 11 | IP: net.LocalHostIP.IP(), 12 | Port: 0, 13 | }) 14 | common.Must(err) 15 | defer conn.Close() 16 | 17 | addr := conn.LocalAddr().(*net.UDPAddr) 18 | return net.Port(addr.Port) 19 | } 20 | -------------------------------------------------------------------------------- /main/commands/all/commands.go: -------------------------------------------------------------------------------- 1 | package all 2 | 3 | import ( 4 | "github.com/xtls/xray-core/main/commands/all/api" 5 | "github.com/xtls/xray-core/main/commands/all/convert" 6 | "github.com/xtls/xray-core/main/commands/all/tls" 7 | "github.com/xtls/xray-core/main/commands/base" 8 | ) 9 | 10 | func init() { 11 | base.RootCommand.Commands = append( 12 | base.RootCommand.Commands, 13 | api.CmdAPI, 14 | convert.CmdConvert, 15 | tls.CmdTLS, 16 | cmdUUID, 17 | cmdX25519, 18 | cmdWG, 19 | cmdMLDSA65, 20 | cmdMLKEM768, 21 | cmdVLESSEnc, 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /common/protocol/time_test.go: -------------------------------------------------------------------------------- 1 | package protocol_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | . "github.com/xtls/xray-core/common/protocol" 8 | ) 9 | 10 | func TestGenerateRandomInt64InRange(t *testing.T) { 11 | base := time.Now().Unix() 12 | delta := 100 13 | generator := NewTimestampGenerator(Timestamp(base), delta) 14 | 15 | for i := 0; i < 100; i++ { 16 | val := int64(generator()) 17 | if val > base+int64(delta) || val < base-int64(delta) { 18 | t.Error(val, " not between ", base-int64(delta), " and ", base+int64(delta)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /common/net/address.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.net; 4 | option csharp_namespace = "Xray.Common.Net"; 5 | option go_package = "github.com/xtls/xray-core/common/net"; 6 | option java_package = "com.xray.common.net"; 7 | option java_multiple_files = true; 8 | 9 | // Address of a network host. It may be either an IP address or a domain 10 | // address. 11 | message IPOrDomain { 12 | oneof address { 13 | // IP address. Must by either 4 or 16 bytes. 14 | bytes ip = 1; 15 | 16 | // Domain address. 17 | string domain = 2; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /proxy/vmess/encoding/encoding.go: -------------------------------------------------------------------------------- 1 | package encoding 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/net" 5 | "github.com/xtls/xray-core/common/protocol" 6 | ) 7 | 8 | const ( 9 | Version = byte(1) 10 | ) 11 | 12 | var addrParser = protocol.NewAddressParser( 13 | protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4), 14 | protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain), 15 | protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6), 16 | protocol.PortThenAddress(), 17 | ) 18 | -------------------------------------------------------------------------------- /transport/internet/headers/srtp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.headers.srtp; 4 | option csharp_namespace = "Xray.Transport.Internet.Headers.Srtp"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/headers/srtp"; 6 | option java_package = "com.xray.transport.internet.headers.srtp"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | uint32 version = 1; 11 | bool padding = 2; 12 | bool extension = 3; 13 | uint32 csrc_count = 4; 14 | bool marker = 5; 15 | uint32 payload_type = 6; 16 | } 17 | -------------------------------------------------------------------------------- /app/dns/fakedns/fakedns.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.dns.fakedns; 4 | option csharp_namespace = "Xray.App.Dns.Fakedns"; 5 | option go_package = "github.com/xtls/xray-core/app/dns/fakedns"; 6 | option java_package = "com.xray.app.dns.fakedns"; 7 | option java_multiple_files = true; 8 | 9 | message FakeDnsPool{ 10 | string ip_pool = 1; //CIDR of IP pool used as fake DNS IP 11 | int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address 12 | } 13 | 14 | message FakeDnsPoolMulti{ 15 | repeated FakeDnsPool pools = 1; 16 | } -------------------------------------------------------------------------------- /transport/internet/sockopt.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | func isTCPSocket(network string) bool { 4 | switch network { 5 | case "tcp", "tcp4", "tcp6": 6 | return true 7 | default: 8 | return false 9 | } 10 | } 11 | 12 | func isUDPSocket(network string) bool { 13 | switch network { 14 | case "udp", "udp4", "udp6": 15 | return true 16 | default: 17 | return false 18 | } 19 | } 20 | 21 | func (v *SocketConfig) ParseTFOValue() int { 22 | if v.Tfo == 0 { 23 | return -1 24 | } 25 | tfo := int(v.Tfo) 26 | if tfo < 0 { 27 | tfo = 0 28 | } 29 | return tfo 30 | } 31 | -------------------------------------------------------------------------------- /common/peer/latency.go: -------------------------------------------------------------------------------- 1 | package peer 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type Latency interface { 8 | Value() uint64 9 | } 10 | 11 | type HasLatency interface { 12 | ConnectionLatency() Latency 13 | HandshakeLatency() Latency 14 | } 15 | 16 | type AverageLatency struct { 17 | access sync.Mutex 18 | value uint64 19 | } 20 | 21 | func (al *AverageLatency) Update(newValue uint64) { 22 | al.access.Lock() 23 | defer al.access.Unlock() 24 | 25 | al.value = (al.value + newValue*2) / 3 26 | } 27 | 28 | func (al *AverageLatency) Value() uint64 { 29 | return al.value 30 | } 31 | -------------------------------------------------------------------------------- /common/net/net.go: -------------------------------------------------------------------------------- 1 | // Package net is a drop-in replacement to Golang's net package, with some more functionalities. 2 | package net // import "github.com/xtls/xray-core/common/net" 3 | 4 | import "time" 5 | 6 | // defines the maximum time an idle TCP session can survive in the tunnel, so 7 | // it should be consistent across HTTP versions and with other transports. 8 | const ConnIdleTimeout = 300 * time.Second 9 | 10 | // consistent with quic-go 11 | const QuicgoH3KeepAlivePeriod = 10 * time.Second 12 | 13 | // consistent with chrome 14 | const ChromeH2KeepAlivePeriod = 45 * time.Second 15 | -------------------------------------------------------------------------------- /features/dns/fakedns.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/net" 5 | "github.com/xtls/xray-core/features" 6 | ) 7 | 8 | type FakeDNSEngine interface { 9 | features.Feature 10 | GetFakeIPForDomain(domain string) []net.Address 11 | GetDomainFromFakeDNS(ip net.Address) string 12 | } 13 | 14 | var ( 15 | FakeIPv4Pool = "198.18.0.0/15" 16 | FakeIPv6Pool = "fc00::/18" 17 | ) 18 | 19 | type FakeDNSEngineRev0 interface { 20 | FakeDNSEngine 21 | IsIPInIPPool(ip net.Address) bool 22 | GetFakeIPForDomain3(domain string, IPv4, IPv6 bool) []net.Address 23 | } 24 | -------------------------------------------------------------------------------- /main/commands/base/env.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | // CommandEnvHolder is a struct holds the environment info of commands 4 | type CommandEnvHolder struct { 5 | // Executable name of current binary 6 | Exec string 7 | // commands column width of current command 8 | CommandsWidth int 9 | } 10 | 11 | // CommandEnv holds the environment info of commands 12 | var CommandEnv CommandEnvHolder 13 | 14 | func init() { 15 | /* 16 | exec, err := os.Executable() 17 | if err != nil { 18 | return 19 | } 20 | CommandEnv.Exec = path.Base(exec) 21 | */ 22 | CommandEnv.Exec = "xray" 23 | } 24 | -------------------------------------------------------------------------------- /app/stats/counter.go: -------------------------------------------------------------------------------- 1 | package stats 2 | 3 | import "sync/atomic" 4 | 5 | // Counter is an implementation of stats.Counter. 6 | type Counter struct { 7 | value int64 8 | } 9 | 10 | // Value implements stats.Counter. 11 | func (c *Counter) Value() int64 { 12 | return atomic.LoadInt64(&c.value) 13 | } 14 | 15 | // Set implements stats.Counter. 16 | func (c *Counter) Set(newValue int64) int64 { 17 | return atomic.SwapInt64(&c.value, newValue) 18 | } 19 | 20 | // Add implements stats.Counter. 21 | func (c *Counter) Add(delta int64) int64 { 22 | return atomic.AddInt64(&c.value, delta) 23 | } 24 | -------------------------------------------------------------------------------- /proxy/dns/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.dns; 4 | option csharp_namespace = "Xray.Proxy.Dns"; 5 | option go_package = "github.com/xtls/xray-core/proxy/dns"; 6 | option java_package = "com.xray.proxy.dns"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/destination.proto"; 10 | 11 | message Config { 12 | // Server is the DNS server address. If specified, this address overrides the 13 | // original one. 14 | xray.common.net.Endpoint server = 1; 15 | uint32 user_level = 2; 16 | string non_IP_query = 3; 17 | repeated int32 block_types = 4; 18 | } 19 | -------------------------------------------------------------------------------- /proxy/vmess/inbound/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vmess.inbound; 4 | option csharp_namespace = "Xray.Proxy.Vmess.Inbound"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vmess/inbound"; 6 | option java_package = "com.xray.proxy.vmess.inbound"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/user.proto"; 10 | 11 | message DetourConfig { 12 | string to = 1; 13 | } 14 | 15 | message DefaultConfig { 16 | uint32 level = 2; 17 | } 18 | 19 | message Config { 20 | repeated xray.common.protocol.User user = 1; 21 | DefaultConfig default = 2; 22 | } 23 | -------------------------------------------------------------------------------- /common/net/port.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.net; 4 | option csharp_namespace = "Xray.Common.Net"; 5 | option go_package = "github.com/xtls/xray-core/common/net"; 6 | option java_package = "com.xray.common.net"; 7 | option java_multiple_files = true; 8 | 9 | // PortRange represents a range of ports. 10 | message PortRange { 11 | // The port that this range starts from. 12 | uint32 From = 1; 13 | // The port that this range ends with (inclusive). 14 | uint32 To = 2; 15 | } 16 | 17 | // PortList is a list of ports. 18 | message PortList { 19 | repeated PortRange range = 1; 20 | } 21 | -------------------------------------------------------------------------------- /common/ctx/context.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import "context" 4 | 5 | type SessionKey int 6 | 7 | // ID of a session. 8 | type ID uint32 9 | 10 | const ( 11 | idSessionKey SessionKey = 0 12 | ) 13 | 14 | // ContextWithID returns a new context with the given ID. 15 | func ContextWithID(ctx context.Context, id ID) context.Context { 16 | return context.WithValue(ctx, idSessionKey, id) 17 | } 18 | 19 | // IDFromContext returns ID in this context, or 0 if not contained. 20 | func IDFromContext(ctx context.Context) ID { 21 | if id, ok := ctx.Value(idSessionKey).(ID); ok { 22 | return id 23 | } 24 | return 0 25 | } 26 | -------------------------------------------------------------------------------- /common/strmatcher/full_matcher.go: -------------------------------------------------------------------------------- 1 | package strmatcher 2 | 3 | type FullMatcherGroup struct { 4 | matchers map[string][]uint32 5 | } 6 | 7 | func (g *FullMatcherGroup) Add(domain string, value uint32) { 8 | if g.matchers == nil { 9 | g.matchers = make(map[string][]uint32) 10 | } 11 | 12 | g.matchers[domain] = append(g.matchers[domain], value) 13 | } 14 | 15 | func (g *FullMatcherGroup) addMatcher(m fullMatcher, value uint32) { 16 | g.Add(string(m), value) 17 | } 18 | 19 | func (g *FullMatcherGroup) Match(str string) []uint32 { 20 | if g.matchers == nil { 21 | return nil 22 | } 23 | 24 | return g.matchers[str] 25 | } 26 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | -------------------------------------------------------------------------------- /infra/conf/version.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/xtls/xray-core/app/version" 5 | "github.com/xtls/xray-core/core" 6 | "strconv" 7 | ) 8 | 9 | type VersionConfig struct { 10 | MinVersion string `json:"min"` 11 | MaxVersion string `json:"max"` 12 | } 13 | 14 | func (c *VersionConfig) Build() (*version.Config, error) { 15 | coreVersion := strconv.Itoa(int(core.Version_x)) + "." + strconv.Itoa(int(core.Version_y)) + "." + strconv.Itoa(int(core.Version_z)) 16 | 17 | return &version.Config{ 18 | CoreVersion: coreVersion, 19 | MinVersion: c.MinVersion, 20 | MaxVersion: c.MaxVersion, 21 | }, nil 22 | } 23 | -------------------------------------------------------------------------------- /main/version.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/xtls/xray-core/core" 7 | "github.com/xtls/xray-core/main/commands/base" 8 | ) 9 | 10 | var cmdVersion = &base.Command{ 11 | UsageLine: "{{.Exec}} version", 12 | Short: "Show current version of Xray", 13 | Long: `Version prints the build information for Xray executables. 14 | `, 15 | Run: executeVersion, 16 | } 17 | 18 | func executeVersion(cmd *base.Command, args []string) { 19 | printVersion() 20 | } 21 | 22 | func printVersion() { 23 | version := core.VersionStatement() 24 | for _, s := range version { 25 | fmt.Println(s) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/dispatcher/stats.go: -------------------------------------------------------------------------------- 1 | package dispatcher 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/common/buf" 6 | "github.com/xtls/xray-core/features/stats" 7 | ) 8 | 9 | type SizeStatWriter struct { 10 | Counter stats.Counter 11 | Writer buf.Writer 12 | } 13 | 14 | func (w *SizeStatWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { 15 | w.Counter.Add(int64(mb.Len())) 16 | return w.Writer.WriteMultiBuffer(mb) 17 | } 18 | 19 | func (w *SizeStatWriter) Close() error { 20 | return common.Close(w.Writer) 21 | } 22 | 23 | func (w *SizeStatWriter) Interrupt() { 24 | common.Interrupt(w.Writer) 25 | } 26 | -------------------------------------------------------------------------------- /transport/internet/sockopt_other.go: -------------------------------------------------------------------------------- 1 | //go:build js || netbsd || openbsd || solaris 2 | // +build js netbsd openbsd solaris 3 | 4 | package internet 5 | 6 | func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error { 7 | return nil 8 | } 9 | 10 | func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { 11 | return nil 12 | } 13 | 14 | func bindAddr(fd uintptr, ip []byte, port uint32) error { 15 | return nil 16 | } 17 | 18 | func setReuseAddr(fd uintptr) error { 19 | return nil 20 | } 21 | 22 | func setReusePort(fd uintptr) error { 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /transport/internet/websocket/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.websocket; 4 | option csharp_namespace = "Xray.Transport.Internet.Websocket"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/websocket"; 6 | option java_package = "com.xray.transport.internet.websocket"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | string host = 1; 11 | string path = 2; // URL path to the WebSocket service. Empty value means root(/). 12 | map header = 3; 13 | bool accept_proxy_protocol = 4; 14 | uint32 ed = 5; 15 | uint32 heartbeatPeriod = 6; 16 | } 17 | -------------------------------------------------------------------------------- /common/protocol/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.common.protocol; 4 | option csharp_namespace = "Xray.Common.Protocol"; 5 | option go_package = "github.com/xtls/xray-core/common/protocol"; 6 | option java_package = "com.xray.common.protocol"; 7 | option java_multiple_files = true; 8 | 9 | import "common/serial/typed_message.proto"; 10 | 11 | // User is a generic user for all protocols. 12 | message User { 13 | uint32 level = 1; 14 | string email = 2; 15 | 16 | // Protocol specific account information. Must be the account proto in one of 17 | // the proxies. 18 | xray.common.serial.TypedMessage account = 3; 19 | } 20 | -------------------------------------------------------------------------------- /common/signal/pubsub/pubsub_test.go: -------------------------------------------------------------------------------- 1 | package pubsub_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/signal/pubsub" 7 | ) 8 | 9 | func TestPubsub(t *testing.T) { 10 | service := NewService() 11 | 12 | sub := service.Subscribe("a") 13 | service.Publish("a", 1) 14 | 15 | select { 16 | case v := <-sub.Wait(): 17 | if v != 1 { 18 | t.Error("expected subscribed value 1, but got ", v) 19 | } 20 | default: 21 | t.Fail() 22 | } 23 | 24 | sub.Close() 25 | service.Publish("a", 2) 26 | 27 | select { 28 | case <-sub.Wait(): 29 | t.Fail() 30 | default: 31 | } 32 | 33 | service.Cleanup() 34 | } 35 | -------------------------------------------------------------------------------- /common/signal/semaphore/semaphore.go: -------------------------------------------------------------------------------- 1 | package semaphore 2 | 3 | // Instance is an implementation of semaphore. 4 | type Instance struct { 5 | token chan struct{} 6 | } 7 | 8 | // New create a new Semaphore with n permits. 9 | func New(n int) *Instance { 10 | s := &Instance{ 11 | token: make(chan struct{}, n), 12 | } 13 | for i := 0; i < n; i++ { 14 | s.token <- struct{}{} 15 | } 16 | return s 17 | } 18 | 19 | // Wait returns a channel for acquiring a permit. 20 | func (s *Instance) Wait() <-chan struct{} { 21 | return s.token 22 | } 23 | 24 | // Signal releases a permit into the semaphore. 25 | func (s *Instance) Signal() { 26 | s.token <- struct{}{} 27 | } 28 | -------------------------------------------------------------------------------- /app/dns/nameserver_local_test.go: -------------------------------------------------------------------------------- 1 | package dns_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | . "github.com/xtls/xray-core/app/dns" 9 | "github.com/xtls/xray-core/common" 10 | "github.com/xtls/xray-core/features/dns" 11 | ) 12 | 13 | func TestLocalNameServer(t *testing.T) { 14 | s := NewLocalNameServer() 15 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 16 | ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{ 17 | IPv4Enable: true, 18 | IPv6Enable: true, 19 | FakeEnable: false, 20 | }) 21 | cancel() 22 | common.Must(err) 23 | if len(ips) == 0 { 24 | t.Error("expect some ips, but got 0") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/mux/frame_test.go: -------------------------------------------------------------------------------- 1 | package mux_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "github.com/xtls/xray-core/common/buf" 8 | "github.com/xtls/xray-core/common/mux" 9 | "github.com/xtls/xray-core/common/net" 10 | ) 11 | 12 | func BenchmarkFrameWrite(b *testing.B) { 13 | frame := mux.FrameMetadata{ 14 | Target: net.TCPDestination(net.DomainAddress("www.example.com"), net.Port(80)), 15 | SessionID: 1, 16 | SessionStatus: mux.SessionStatusNew, 17 | } 18 | writer := buf.New() 19 | defer writer.Release() 20 | 21 | for i := 0; i < b.N; i++ { 22 | common.Must(frame.WriteTo(writer)) 23 | writer.Clear() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /proxy/blackhole/config_test.go: -------------------------------------------------------------------------------- 1 | package blackhole_test 2 | 3 | import ( 4 | "bufio" 5 | "net/http" 6 | "testing" 7 | 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/common/buf" 10 | . "github.com/xtls/xray-core/proxy/blackhole" 11 | ) 12 | 13 | func TestHTTPResponse(t *testing.T) { 14 | buffer := buf.New() 15 | 16 | httpResponse := new(HTTPResponse) 17 | httpResponse.WriteTo(buf.NewWriter(buffer)) 18 | 19 | reader := bufio.NewReader(buffer) 20 | response, err := http.ReadResponse(reader, nil) 21 | common.Must(err) 22 | 23 | if response.StatusCode != 403 { 24 | t.Error("expected status code 403, but got ", response.StatusCode) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /main/confloader/confloader.go: -------------------------------------------------------------------------------- 1 | package confloader 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "os" 7 | 8 | "github.com/xtls/xray-core/common/errors" 9 | ) 10 | 11 | type ( 12 | configFileLoader func(string) (io.Reader, error) 13 | ) 14 | 15 | var ( 16 | EffectiveConfigFileLoader configFileLoader 17 | ) 18 | 19 | // LoadConfig reads from a path/url/stdin 20 | // actual work is in external module 21 | func LoadConfig(file string) (io.Reader, error) { 22 | if EffectiveConfigFileLoader == nil { 23 | errors.LogInfo(context.Background(), "external config module not loaded, reading from stdin") 24 | return os.Stdin, nil 25 | } 26 | return EffectiveConfigFileLoader(file) 27 | } 28 | -------------------------------------------------------------------------------- /proxy/vmess/aead/kdf.go: -------------------------------------------------------------------------------- 1 | package aead 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha256" 6 | "hash" 7 | ) 8 | 9 | type hash2 struct { 10 | hash.Hash 11 | } 12 | 13 | func KDF(key []byte, path ...string) []byte { 14 | hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF)) 15 | 16 | for _, v := range path { 17 | first := true 18 | hmacf = hmac.New(func() hash.Hash { 19 | if first { 20 | first = false 21 | return hash2{hmacf} 22 | } 23 | return hmacf 24 | }, []byte(v)) 25 | } 26 | hmacf.Write(key) 27 | return hmacf.Sum(nil) 28 | } 29 | 30 | func KDF16(key []byte, path ...string) []byte { 31 | r := KDF(key, path...) 32 | return r[:16] 33 | } 34 | -------------------------------------------------------------------------------- /transport/internet/headers/wechat/wechat_test.go: -------------------------------------------------------------------------------- 1 | package wechat_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/buf" 9 | . "github.com/xtls/xray-core/transport/internet/headers/wechat" 10 | ) 11 | 12 | func TestUTPWrite(t *testing.T) { 13 | videoRaw, err := NewVideoChat(context.Background(), &VideoConfig{}) 14 | common.Must(err) 15 | 16 | video := videoRaw.(*VideoChat) 17 | 18 | payload := buf.New() 19 | video.Serialize(payload.Extend(video.Size())) 20 | 21 | if payload.Len() != video.Size() { 22 | t.Error("expected payload size ", video.Size(), " but got ", payload.Len()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/log/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.log; 4 | option csharp_namespace = "Xray.App.Log"; 5 | option go_package = "github.com/xtls/xray-core/app/log"; 6 | option java_package = "com.xray.app.log"; 7 | option java_multiple_files = true; 8 | 9 | import "common/log/log.proto"; 10 | 11 | enum LogType { 12 | None = 0; 13 | Console = 1; 14 | File = 2; 15 | Event = 3; 16 | } 17 | 18 | message Config { 19 | LogType error_log_type = 1; 20 | xray.common.log.Severity error_log_level = 2; 21 | string error_log_path = 3; 22 | 23 | LogType access_log_type = 4; 24 | string access_log_path = 5; 25 | bool enable_dns_log = 6; 26 | string mask_address= 7; 27 | } 28 | -------------------------------------------------------------------------------- /proxy/vmess/account.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vmess; 4 | option csharp_namespace = "Xray.Proxy.Vmess"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vmess"; 6 | option java_package = "com.xray.proxy.vmess"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/headers.proto"; 10 | 11 | message Account { 12 | // ID of the account, in the form of a UUID, e.g., 13 | // "66ad4540-b58c-4ad2-9926-ea63445a9b57". 14 | string id = 1; 15 | // Security settings. Only applies to client side. 16 | xray.common.protocol.SecurityConfig security_settings = 3; 17 | // Define tests enabled for this account 18 | string tests_enabled = 4; 19 | } 20 | -------------------------------------------------------------------------------- /common/platform/windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package platform 5 | 6 | import "path/filepath" 7 | 8 | func LineSeparator() string { 9 | return "\r\n" 10 | } 11 | 12 | // GetAssetLocation searches for `file` in the env dir and the executable dir 13 | func GetAssetLocation(file string) string { 14 | assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir) 15 | return filepath.Join(assetPath, file) 16 | } 17 | 18 | // GetCertLocation searches for `file` in the env dir and the executable dir 19 | func GetCertLocation(file string) string { 20 | certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir) 21 | return filepath.Join(certPath, file) 22 | } 23 | -------------------------------------------------------------------------------- /infra/conf/metrics.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/xtls/xray-core/app/metrics" 5 | "github.com/xtls/xray-core/common/errors" 6 | ) 7 | 8 | type MetricsConfig struct { 9 | Tag string `json:"tag"` 10 | Listen string `json:"listen"` 11 | } 12 | 13 | func (c *MetricsConfig) Build() (*metrics.Config, error) { 14 | if c.Listen == "" && c.Tag == "" { 15 | return nil, errors.New("Metrics must have a tag or listen address.") 16 | } 17 | // If the tag is empty but have "listen" set a default "Metrics" for compatibility. 18 | if c.Tag == "" { 19 | c.Tag = "Metrics" 20 | } 21 | 22 | return &metrics.Config{ 23 | Tag: c.Tag, 24 | Listen: c.Listen, 25 | }, nil 26 | } 27 | -------------------------------------------------------------------------------- /proxy/dokodemo/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.dokodemo; 4 | option csharp_namespace = "Xray.Proxy.Dokodemo"; 5 | option go_package = "github.com/xtls/xray-core/proxy/dokodemo"; 6 | option java_package = "com.xray.proxy.dokodemo"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/address.proto"; 10 | import "common/net/network.proto"; 11 | 12 | message Config { 13 | xray.common.net.IPOrDomain address = 1; 14 | uint32 port = 2; 15 | 16 | map port_map = 3; 17 | 18 | // List of networks that the Dokodemo accepts. 19 | repeated xray.common.net.Network networks = 7; 20 | 21 | bool follow_redirect = 5; 22 | uint32 user_level = 6; 23 | } 24 | -------------------------------------------------------------------------------- /app/observatory/explainErrors.go: -------------------------------------------------------------------------------- 1 | package observatory 2 | 3 | import "github.com/xtls/xray-core/common/errors" 4 | 5 | type errorCollector struct { 6 | errors *errors.Error 7 | } 8 | 9 | func (e *errorCollector) SubmitError(err error) { 10 | if e.errors == nil { 11 | e.errors = errors.New("underlying connection error").Base(err) 12 | return 13 | } 14 | e.errors = e.errors.Base(errors.New("underlying connection error").Base(err)) 15 | } 16 | 17 | func newErrorCollector() *errorCollector { 18 | return &errorCollector{} 19 | } 20 | 21 | func (e *errorCollector) UnderlyingError() error { 22 | if e.errors == nil { 23 | return errors.New("failed to produce report") 24 | } 25 | return e.errors 26 | } 27 | -------------------------------------------------------------------------------- /app/commander/service.go: -------------------------------------------------------------------------------- 1 | package commander 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "google.golang.org/grpc" 8 | "google.golang.org/grpc/reflection" 9 | ) 10 | 11 | // Service is a Commander service. 12 | type Service interface { 13 | // Register registers the service itself to a gRPC server. 14 | Register(*grpc.Server) 15 | } 16 | 17 | type reflectionService struct{} 18 | 19 | func (r reflectionService) Register(s *grpc.Server) { 20 | reflection.Register(s) 21 | } 22 | 23 | func init() { 24 | common.Must(common.RegisterConfig((*ReflectionConfig)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) { 25 | return reflectionService{}, nil 26 | })) 27 | } 28 | -------------------------------------------------------------------------------- /common/log/log_test.go: -------------------------------------------------------------------------------- 1 | package log_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | "github.com/xtls/xray-core/common/log" 8 | "github.com/xtls/xray-core/common/net" 9 | ) 10 | 11 | type testLogger struct { 12 | value string 13 | } 14 | 15 | func (l *testLogger) Handle(msg log.Message) { 16 | l.value = msg.String() 17 | } 18 | 19 | func TestLogRecord(t *testing.T) { 20 | var logger testLogger 21 | log.RegisterHandler(&logger) 22 | 23 | ip := "8.8.8.8" 24 | log.Record(&log.GeneralMessage{ 25 | Severity: log.Severity_Error, 26 | Content: net.ParseAddress(ip), 27 | }) 28 | 29 | if diff := cmp.Diff("[Error] "+ip, logger.value); diff != "" { 30 | t.Error(diff) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /transport/internet/headers/utp/utp_test.go: -------------------------------------------------------------------------------- 1 | package utp_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/buf" 9 | . "github.com/xtls/xray-core/transport/internet/headers/utp" 10 | ) 11 | 12 | func TestUTPWrite(t *testing.T) { 13 | content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'} 14 | utpRaw, err := New(context.Background(), &Config{}) 15 | common.Must(err) 16 | 17 | utp := utpRaw.(*UTP) 18 | 19 | payload := buf.New() 20 | utp.Serialize(payload.Extend(utp.Size())) 21 | payload.Write(content) 22 | 23 | if payload.Len() != int32(len(content))+utp.Size() { 24 | t.Error("unexpected payload length: ", payload.Len()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /transport/internet/headers/wireguard/wireguard.go: -------------------------------------------------------------------------------- 1 | package wireguard 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/xtls/xray-core/common" 7 | ) 8 | 9 | type Wireguard struct{} 10 | 11 | func (Wireguard) Size() int32 { 12 | return 4 13 | } 14 | 15 | // Serialize implements PacketHeader. 16 | func (Wireguard) Serialize(b []byte) { 17 | b[0] = 0x04 18 | b[1] = 0x00 19 | b[2] = 0x00 20 | b[3] = 0x00 21 | } 22 | 23 | // NewWireguard returns a new VideoChat instance based on given config. 24 | func NewWireguard(ctx context.Context, config interface{}) (interface{}, error) { 25 | return Wireguard{}, nil 26 | } 27 | 28 | func init() { 29 | common.Must(common.RegisterConfig((*WireguardConfig)(nil), NewWireguard)) 30 | } 31 | -------------------------------------------------------------------------------- /transport/internet/websocket/config.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "github.com/xtls/xray-core/transport/internet" 8 | ) 9 | 10 | func (c *Config) GetNormalizedPath() string { 11 | path := c.Path 12 | if path == "" { 13 | return "/" 14 | } 15 | if path[0] != '/' { 16 | return "/" + path 17 | } 18 | return path 19 | } 20 | 21 | func (c *Config) GetRequestHeader() http.Header { 22 | header := http.Header{} 23 | for k, v := range c.Header { 24 | header.Add(k, v) 25 | } 26 | return header 27 | } 28 | 29 | func init() { 30 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 31 | return new(Config) 32 | })) 33 | } 34 | -------------------------------------------------------------------------------- /core/annotations.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | // Annotation is a concept in Xray. This struct is only for documentation. It is not used anywhere. 4 | // Annotations begin with "xray:" in comment, as metadata of functions or types. 5 | type Annotation struct { 6 | // API is for types or functions that can be used in other libs. Possible values are: 7 | // 8 | // * xray:api:beta for types or functions that are ready for use, but maybe changed in the future. 9 | // * xray:api:stable for types or functions with guarantee of backward compatibility. 10 | // * xray:api:deprecated for types or functions that should not be used anymore. 11 | // 12 | // Types or functions without api annotation should not be used externally. 13 | API string 14 | } 15 | -------------------------------------------------------------------------------- /main/commands/all/wg.go: -------------------------------------------------------------------------------- 1 | package all 2 | 3 | import ( 4 | "github.com/xtls/xray-core/main/commands/base" 5 | ) 6 | 7 | var cmdWG = &base.Command{ 8 | UsageLine: `{{.Exec}} wg [-i "private key (base64.StdEncoding)"]`, 9 | Short: `Generate key pair for X25519 key exchange (WireGuard)`, 10 | Long: ` 11 | Generate key pair for X25519 key exchange (WireGuard). 12 | 13 | Random: {{.Exec}} wg 14 | 15 | From private key: {{.Exec}} wg -i "private key (base64.StdEncoding)" 16 | `, 17 | } 18 | 19 | func init() { 20 | cmdWG.Run = executeWG // break init loop 21 | } 22 | 23 | var input_wireguard = cmdWG.Flag.String("i", "", "") 24 | 25 | func executeWG(cmd *base.Command, args []string) { 26 | Curve25519Genkey(true, *input_wireguard) 27 | } 28 | -------------------------------------------------------------------------------- /app/observatory/command/command.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.core.app.observatory.command; 4 | option csharp_namespace = "Xray.Core.App.Observatory.Command"; 5 | option go_package = "github.com/xtls/xray-core/app/observatory/command"; 6 | option java_package = "com.xray.core.app.observatory.command"; 7 | option java_multiple_files = true; 8 | 9 | import "app/observatory/config.proto"; 10 | 11 | message GetOutboundStatusRequest { 12 | } 13 | 14 | message GetOutboundStatusResponse { 15 | xray.core.app.observatory.ObservationResult status = 1; 16 | } 17 | 18 | service ObservatoryService { 19 | rpc GetOutboundStatus(GetOutboundStatusRequest) 20 | returns (GetOutboundStatusResponse) {} 21 | } 22 | 23 | 24 | message Config {} -------------------------------------------------------------------------------- /app/reverse/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.reverse; 4 | option csharp_namespace = "Xray.Proxy.Reverse"; 5 | option go_package = "github.com/xtls/xray-core/app/reverse"; 6 | option java_package = "com.xray.proxy.reverse"; 7 | option java_multiple_files = true; 8 | 9 | message Control { 10 | enum State { 11 | ACTIVE = 0; 12 | DRAIN = 1; 13 | } 14 | 15 | State state = 1; 16 | bytes random = 99; 17 | } 18 | 19 | message BridgeConfig { 20 | string tag = 1; 21 | string domain = 2; 22 | } 23 | 24 | message PortalConfig { 25 | string tag = 1; 26 | string domain = 2; 27 | } 28 | 29 | message Config { 30 | repeated BridgeConfig bridge_config = 1; 31 | repeated PortalConfig portal_config = 2; 32 | } 33 | -------------------------------------------------------------------------------- /common/buf/readv_unix.go: -------------------------------------------------------------------------------- 1 | //go:build illumos 2 | // +build illumos 3 | 4 | package buf 5 | 6 | import "golang.org/x/sys/unix" 7 | 8 | type unixReader struct { 9 | iovs [][]byte 10 | } 11 | 12 | func (r *unixReader) Init(bs []*Buffer) { 13 | iovs := r.iovs 14 | if iovs == nil { 15 | iovs = make([][]byte, 0, len(bs)) 16 | } 17 | for _, b := range bs { 18 | iovs = append(iovs, b.v) 19 | } 20 | r.iovs = iovs 21 | } 22 | 23 | func (r *unixReader) Read(fd uintptr) int32 { 24 | n, e := unix.Readv(int(fd), r.iovs) 25 | if e != nil { 26 | return -1 27 | } 28 | return int32(n) 29 | } 30 | 31 | func (r *unixReader) Clear() { 32 | r.iovs = r.iovs[:0] 33 | } 34 | 35 | func newMultiReader() multiReader { 36 | return &unixReader{} 37 | } 38 | -------------------------------------------------------------------------------- /common/signal/notifier.go: -------------------------------------------------------------------------------- 1 | package signal 2 | 3 | // Notifier is a utility for notifying changes. The change producer may notify changes multiple time, and the consumer may get notified asynchronously. 4 | type Notifier struct { 5 | c chan struct{} 6 | } 7 | 8 | // NewNotifier creates a new Notifier. 9 | func NewNotifier() *Notifier { 10 | return &Notifier{ 11 | c: make(chan struct{}, 1), 12 | } 13 | } 14 | 15 | // Signal signals a change, usually by producer. This method never blocks. 16 | func (n *Notifier) Signal() { 17 | select { 18 | case n.c <- struct{}{}: 19 | default: 20 | } 21 | } 22 | 23 | // Wait returns a channel for waiting for changes. The returned channel never gets closed. 24 | func (n *Notifier) Wait() <-chan struct{} { 25 | return n.c 26 | } 27 | -------------------------------------------------------------------------------- /proxy/http/config.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "google.golang.org/protobuf/proto" 5 | 6 | "github.com/xtls/xray-core/common/protocol" 7 | ) 8 | 9 | func (a *Account) Equals(another protocol.Account) bool { 10 | if account, ok := another.(*Account); ok { 11 | return a.Username == account.Username 12 | } 13 | return false 14 | } 15 | 16 | func (a *Account) ToProto() proto.Message { 17 | return a 18 | } 19 | 20 | func (a *Account) AsAccount() (protocol.Account, error) { 21 | return a, nil 22 | } 23 | 24 | func (sc *ServerConfig) HasAccount(username, password string) bool { 25 | if sc.Accounts == nil { 26 | return false 27 | } 28 | 29 | p, found := sc.Accounts[username] 30 | if !found { 31 | return false 32 | } 33 | return p == password 34 | } 35 | -------------------------------------------------------------------------------- /transport/internet/headers/tls/dtls_test.go: -------------------------------------------------------------------------------- 1 | package tls_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/buf" 9 | . "github.com/xtls/xray-core/transport/internet/headers/tls" 10 | ) 11 | 12 | func TestDTLSWrite(t *testing.T) { 13 | content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'} 14 | dtlsRaw, err := New(context.Background(), &PacketConfig{}) 15 | common.Must(err) 16 | 17 | dtls := dtlsRaw.(*DTLS) 18 | 19 | payload := buf.New() 20 | dtls.Serialize(payload.Extend(dtls.Size())) 21 | payload.Write(content) 22 | 23 | if payload.Len() != int32(len(content))+dtls.Size() { 24 | t.Error("payload len: ", payload.Len(), " want ", int32(len(content))+dtls.Size()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /transport/internet/stat/connection.go: -------------------------------------------------------------------------------- 1 | package stat 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/xtls/xray-core/features/stats" 7 | ) 8 | 9 | type Connection interface { 10 | net.Conn 11 | } 12 | 13 | type CounterConnection struct { 14 | Connection 15 | ReadCounter stats.Counter 16 | WriteCounter stats.Counter 17 | } 18 | 19 | func (c *CounterConnection) Read(b []byte) (int, error) { 20 | nBytes, err := c.Connection.Read(b) 21 | if c.ReadCounter != nil { 22 | c.ReadCounter.Add(int64(nBytes)) 23 | } 24 | 25 | return nBytes, err 26 | } 27 | 28 | func (c *CounterConnection) Write(b []byte) (int, error) { 29 | nBytes, err := c.Connection.Write(b) 30 | if c.WriteCounter != nil { 31 | c.WriteCounter.Add(int64(nBytes)) 32 | } 33 | return nBytes, err 34 | } 35 | -------------------------------------------------------------------------------- /common/serial/string.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // ToString serializes an arbitrary value into string. 9 | func ToString(v interface{}) string { 10 | if v == nil { 11 | return "" 12 | } 13 | 14 | switch value := v.(type) { 15 | case string: 16 | return value 17 | case *string: 18 | return *value 19 | case fmt.Stringer: 20 | return value.String() 21 | case error: 22 | return value.Error() 23 | default: 24 | return fmt.Sprintf("%+v", value) 25 | } 26 | } 27 | 28 | // Concat concatenates all input into a single string. 29 | func Concat(v ...interface{}) string { 30 | builder := strings.Builder{} 31 | for _, value := range v { 32 | builder.WriteString(ToString(value)) 33 | } 34 | return builder.String() 35 | } 36 | -------------------------------------------------------------------------------- /infra/conf/dns_proxy_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | . "github.com/xtls/xray-core/infra/conf" 8 | "github.com/xtls/xray-core/proxy/dns" 9 | ) 10 | 11 | func TestDnsProxyConfig(t *testing.T) { 12 | creator := func() Buildable { 13 | return new(DNSOutboundConfig) 14 | } 15 | 16 | runMultiTestCase(t, []TestCase{ 17 | { 18 | Input: `{ 19 | "address": "8.8.8.8", 20 | "port": 53, 21 | "network": "tcp" 22 | }`, 23 | Parser: loadJSON(creator), 24 | Output: &dns.Config{ 25 | Server: &net.Endpoint{ 26 | Network: net.Network_TCP, 27 | Address: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})), 28 | Port: 53, 29 | }, 30 | }, 31 | }, 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /proxy/vless/account.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vless; 4 | option csharp_namespace = "Xray.Proxy.Vless"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vless"; 6 | option java_package = "com.xray.proxy.vless"; 7 | option java_multiple_files = true; 8 | 9 | message Reverse { 10 | string tag = 1; 11 | } 12 | 13 | message Account { 14 | // ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57". 15 | string id = 1; 16 | // Flow settings. May be "xtls-rprx-vision". 17 | string flow = 2; 18 | 19 | string encryption = 3; 20 | uint32 xorMode = 4; 21 | uint32 seconds = 5; 22 | string padding = 6; 23 | 24 | Reverse reverse = 7; 25 | 26 | uint32 testpre = 8; 27 | repeated uint32 testseed = 9; 28 | } 29 | -------------------------------------------------------------------------------- /transport/internet/dialer_test.go: -------------------------------------------------------------------------------- 1 | package internet_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/common/net" 10 | "github.com/xtls/xray-core/testing/servers/tcp" 11 | . "github.com/xtls/xray-core/transport/internet" 12 | ) 13 | 14 | func TestDialWithLocalAddr(t *testing.T) { 15 | server := &tcp.Server{} 16 | dest, err := server.Start() 17 | common.Must(err) 18 | defer server.Close() 19 | 20 | conn, err := DialSystem(context.Background(), net.TCPDestination(net.LocalHostIP, dest.Port), nil) 21 | common.Must(err) 22 | if r := cmp.Diff(conn.RemoteAddr().String(), "127.0.0.1:"+dest.Port.String()); r != "" { 23 | t.Error(r) 24 | } 25 | conn.Close() 26 | } 27 | -------------------------------------------------------------------------------- /common/protocol/server_spec.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/net" 5 | ) 6 | 7 | type ServerSpec struct { 8 | Destination net.Destination 9 | User *MemoryUser 10 | } 11 | 12 | func NewServerSpec(dest net.Destination, user *MemoryUser) *ServerSpec { 13 | return &ServerSpec{ 14 | Destination: dest, 15 | User: user, 16 | } 17 | } 18 | 19 | func NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) { 20 | dest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port)) 21 | var dUser *MemoryUser 22 | if spec.User != nil { 23 | user, err := spec.User.ToMemoryUser() 24 | if err != nil { 25 | return nil, err 26 | } 27 | dUser = user 28 | } 29 | return NewServerSpec(dest, dUser), nil 30 | } 31 | -------------------------------------------------------------------------------- /infra/conf/blackhole_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common/serial" 7 | . "github.com/xtls/xray-core/infra/conf" 8 | "github.com/xtls/xray-core/proxy/blackhole" 9 | ) 10 | 11 | func TestHTTPResponseJSON(t *testing.T) { 12 | creator := func() Buildable { 13 | return new(BlackholeConfig) 14 | } 15 | 16 | runMultiTestCase(t, []TestCase{ 17 | { 18 | Input: `{ 19 | "response": { 20 | "type": "http" 21 | } 22 | }`, 23 | Parser: loadJSON(creator), 24 | Output: &blackhole.Config{ 25 | Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}), 26 | }, 27 | }, 28 | { 29 | Input: `{}`, 30 | Parser: loadJSON(creator), 31 | Output: &blackhole.Config{}, 32 | }, 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /proxy/socks/config.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "google.golang.org/protobuf/proto" 5 | 6 | "github.com/xtls/xray-core/common/protocol" 7 | ) 8 | 9 | func (a *Account) Equals(another protocol.Account) bool { 10 | if account, ok := another.(*Account); ok { 11 | return a.Username == account.Username 12 | } 13 | return false 14 | } 15 | 16 | func (a *Account) ToProto() proto.Message { 17 | return a 18 | } 19 | 20 | func (a *Account) AsAccount() (protocol.Account, error) { 21 | return a, nil 22 | } 23 | 24 | func (c *ServerConfig) HasAccount(username, password string) bool { 25 | if c.Accounts == nil { 26 | return false 27 | } 28 | storedPassed, found := c.Accounts[username] 29 | if !found { 30 | return false 31 | } 32 | return storedPassed == password 33 | } 34 | -------------------------------------------------------------------------------- /common/antireplay/bloomring.go: -------------------------------------------------------------------------------- 1 | package antireplay 2 | 3 | import ( 4 | "sync" 5 | 6 | ss_bloomring "github.com/v2fly/ss-bloomring" 7 | ) 8 | 9 | type BloomRing struct { 10 | *ss_bloomring.BloomRing 11 | lock *sync.Mutex 12 | } 13 | 14 | func (b BloomRing) Interval() int64 { 15 | return 9999999 16 | } 17 | 18 | func (b BloomRing) Check(sum []byte) bool { 19 | b.lock.Lock() 20 | defer b.lock.Unlock() 21 | if b.Test(sum) { 22 | return false 23 | } 24 | b.Add(sum) 25 | return true 26 | } 27 | 28 | func NewBloomRing() BloomRing { 29 | const ( 30 | DefaultSFCapacity = 1e6 31 | // FalsePositiveRate 32 | DefaultSFFPR = 1e-6 33 | DefaultSFSlot = 10 34 | ) 35 | return BloomRing{ss_bloomring.NewBloomRing(DefaultSFSlot, DefaultSFCapacity, DefaultSFFPR), &sync.Mutex{}} 36 | } 37 | -------------------------------------------------------------------------------- /infra/conf/policy_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common" 7 | . "github.com/xtls/xray-core/infra/conf" 8 | ) 9 | 10 | func TestBufferSize(t *testing.T) { 11 | cases := []struct { 12 | Input int32 13 | Output int32 14 | }{ 15 | { 16 | Input: 0, 17 | Output: 0, 18 | }, 19 | { 20 | Input: -1, 21 | Output: -1, 22 | }, 23 | { 24 | Input: 1, 25 | Output: 1024, 26 | }, 27 | } 28 | 29 | for _, c := range cases { 30 | bs := c.Input 31 | pConf := Policy{ 32 | BufferSize: &bs, 33 | } 34 | p, err := pConf.Build() 35 | common.Must(err) 36 | if p.Buffer.Connection != c.Output { 37 | t.Error("expected buffer size ", c.Output, " but got ", p.Buffer.Connection) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /transport/internet/headers/srtp/srtp_test.go: -------------------------------------------------------------------------------- 1 | package srtp_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/buf" 9 | . "github.com/xtls/xray-core/transport/internet/headers/srtp" 10 | ) 11 | 12 | func TestSRTPWrite(t *testing.T) { 13 | content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'} 14 | srtpRaw, err := New(context.Background(), &Config{}) 15 | common.Must(err) 16 | 17 | srtp := srtpRaw.(*SRTP) 18 | 19 | payload := buf.New() 20 | srtp.Serialize(payload.Extend(srtp.Size())) 21 | payload.Write(content) 22 | 23 | expectedLen := int32(len(content)) + srtp.Size() 24 | if payload.Len() != expectedLen { 25 | t.Error("expected ", expectedLen, " of bytes, but got ", payload.Len()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /proxy/vmess/validator_test.go: -------------------------------------------------------------------------------- 1 | package vmess_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "github.com/xtls/xray-core/common/protocol" 8 | "github.com/xtls/xray-core/common/uuid" 9 | . "github.com/xtls/xray-core/proxy/vmess" 10 | ) 11 | 12 | func toAccount(a *Account) protocol.Account { 13 | account, err := a.AsAccount() 14 | common.Must(err) 15 | return account 16 | } 17 | 18 | func BenchmarkUserValidator(b *testing.B) { 19 | for i := 0; i < b.N; i++ { 20 | v := NewTimedUserValidator() 21 | 22 | for j := 0; j < 1500; j++ { 23 | id := uuid.New() 24 | v.Add(&protocol.MemoryUser{ 25 | Email: "test", 26 | Account: toAccount(&Account{ 27 | Id: id.String(), 28 | }), 29 | }) 30 | } 31 | 32 | common.Close(v) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /transport/pipe/writer.go: -------------------------------------------------------------------------------- 1 | package pipe 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/buf" 5 | ) 6 | 7 | // Writer is a buf.Writer that writes data into a pipe. 8 | type Writer struct { 9 | pipe *pipe 10 | } 11 | 12 | // WriteMultiBuffer implements buf.Writer. 13 | func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error { 14 | return w.pipe.WriteMultiBuffer(mb) 15 | } 16 | 17 | // Close implements io.Closer. After the pipe is closed, writing to the pipe will return io.ErrClosedPipe, while reading will return io.EOF. 18 | func (w *Writer) Close() error { 19 | return w.pipe.Close() 20 | } 21 | 22 | func (w *Writer) Len() int32 { 23 | return w.pipe.Len() 24 | } 25 | 26 | // Interrupt implements common.Interruptible. 27 | func (w *Writer) Interrupt() { 28 | w.pipe.Interrupt() 29 | } 30 | -------------------------------------------------------------------------------- /proxy/vless/inbound/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.vless.inbound; 4 | option csharp_namespace = "Xray.Proxy.Vless.Inbound"; 5 | option go_package = "github.com/xtls/xray-core/proxy/vless/inbound"; 6 | option java_package = "com.xray.proxy.vless.inbound"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/user.proto"; 10 | 11 | message Fallback { 12 | string name = 1; 13 | string alpn = 2; 14 | string path = 3; 15 | string type = 4; 16 | string dest = 5; 17 | uint64 xver = 6; 18 | } 19 | 20 | message Config { 21 | repeated xray.common.protocol.User clients = 1; 22 | repeated Fallback fallbacks = 2; 23 | 24 | string decryption = 3; 25 | uint32 xorMode = 4; 26 | int64 seconds_from = 5; 27 | int64 seconds_to = 6; 28 | string padding = 7; 29 | } 30 | -------------------------------------------------------------------------------- /app/stats/counter_test.go: -------------------------------------------------------------------------------- 1 | package stats_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | . "github.com/xtls/xray-core/app/stats" 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/features/stats" 10 | ) 11 | 12 | func TestStatsCounter(t *testing.T) { 13 | raw, err := common.CreateObject(context.Background(), &Config{}) 14 | common.Must(err) 15 | 16 | m := raw.(stats.Manager) 17 | c, err := m.RegisterCounter("test.counter") 18 | common.Must(err) 19 | 20 | if v := c.Add(1); v != 1 { 21 | t.Fatal("unexpected Add(1) return: ", v, ", wanted ", 1) 22 | } 23 | 24 | if v := c.Set(0); v != 1 { 25 | t.Fatal("unexpected Set(0) return: ", v, ", wanted ", 1) 26 | } 27 | 28 | if v := c.Value(); v != 0 { 29 | t.Fatal("unexpected Value() return: ", v, ", wanted ", 0) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /proxy/vmess/aead/consts.go: -------------------------------------------------------------------------------- 1 | package aead 2 | 3 | const ( 4 | KDFSaltConstAuthIDEncryptionKey = "AES Auth ID Encryption" 5 | KDFSaltConstAEADRespHeaderLenKey = "AEAD Resp Header Len Key" 6 | KDFSaltConstAEADRespHeaderLenIV = "AEAD Resp Header Len IV" 7 | KDFSaltConstAEADRespHeaderPayloadKey = "AEAD Resp Header Key" 8 | KDFSaltConstAEADRespHeaderPayloadIV = "AEAD Resp Header IV" 9 | KDFSaltConstVMessAEADKDF = "VMess AEAD KDF" 10 | KDFSaltConstVMessHeaderPayloadAEADKey = "VMess Header AEAD Key" 11 | KDFSaltConstVMessHeaderPayloadAEADIV = "VMess Header AEAD Nonce" 12 | KDFSaltConstVMessHeaderPayloadLengthAEADKey = "VMess Header AEAD Key_Length" 13 | KDFSaltConstVMessHeaderPayloadLengthAEADIV = "VMess Header AEAD Nonce_Length" 14 | ) 15 | -------------------------------------------------------------------------------- /infra/conf/http_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/infra/conf" 7 | "github.com/xtls/xray-core/proxy/http" 8 | ) 9 | 10 | func TestHTTPServerConfig(t *testing.T) { 11 | creator := func() Buildable { 12 | return new(HTTPServerConfig) 13 | } 14 | 15 | runMultiTestCase(t, []TestCase{ 16 | { 17 | Input: `{ 18 | "accounts": [ 19 | { 20 | "user": "my-username", 21 | "pass": "my-password" 22 | } 23 | ], 24 | "allowTransparent": true, 25 | "userLevel": 1 26 | }`, 27 | Parser: loadJSON(creator), 28 | Output: &http.ServerConfig{ 29 | Accounts: map[string]string{ 30 | "my-username": "my-password", 31 | }, 32 | AllowTransparent: true, 33 | UserLevel: 1, 34 | }, 35 | }, 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /infra/conf/cfgcommon/duration/duration_test.go: -------------------------------------------------------------------------------- 1 | package duration_test 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | "time" 7 | 8 | "github.com/xtls/xray-core/infra/conf/cfgcommon/duration" 9 | ) 10 | 11 | type testWithDuration struct { 12 | Duration duration.Duration 13 | } 14 | 15 | func TestDurationJSON(t *testing.T) { 16 | expected := &testWithDuration{ 17 | Duration: duration.Duration(time.Hour), 18 | } 19 | data, err := json.Marshal(expected) 20 | if err != nil { 21 | t.Error(err) 22 | return 23 | } 24 | actual := &testWithDuration{} 25 | err = json.Unmarshal(data, &actual) 26 | if err != nil { 27 | t.Error(err) 28 | return 29 | } 30 | if actual.Duration != expected.Duration { 31 | t.Errorf("expected: %s, actual: %s", time.Duration(expected.Duration), time.Duration(actual.Duration)) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /transport/internet/kcp/io_test.go: -------------------------------------------------------------------------------- 1 | package kcp_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/transport/internet/kcp" 7 | ) 8 | 9 | func TestKCPPacketReader(t *testing.T) { 10 | reader := KCPPacketReader{ 11 | Security: &SimpleAuthenticator{}, 12 | } 13 | 14 | testCases := []struct { 15 | Input []byte 16 | Output []Segment 17 | }{ 18 | { 19 | Input: []byte{}, 20 | Output: nil, 21 | }, 22 | { 23 | Input: []byte{1}, 24 | Output: nil, 25 | }, 26 | } 27 | 28 | for _, testCase := range testCases { 29 | seg := reader.Read(testCase.Input) 30 | if testCase.Output == nil && seg != nil { 31 | t.Errorf("Expect nothing returned, but actually %v", seg) 32 | } else if testCase.Output != nil && seg == nil { 33 | t.Errorf("Expect some output, but got nil") 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /proxy/trojan/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.trojan; 4 | option csharp_namespace = "Xray.Proxy.Trojan"; 5 | option go_package = "github.com/xtls/xray-core/proxy/trojan"; 6 | option java_package = "com.xray.proxy.trojan"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/user.proto"; 10 | import "common/protocol/server_spec.proto"; 11 | 12 | message Account { 13 | string password = 1; 14 | } 15 | 16 | message Fallback { 17 | string name = 1; 18 | string alpn = 2; 19 | string path = 3; 20 | string type = 4; 21 | string dest = 5; 22 | uint64 xver = 6; 23 | } 24 | 25 | message ClientConfig { 26 | xray.common.protocol.ServerEndpoint server = 1; 27 | } 28 | 29 | message ServerConfig { 30 | repeated xray.common.protocol.User users = 1; 31 | repeated Fallback fallbacks = 2; 32 | } 33 | -------------------------------------------------------------------------------- /transport/internet/udp/dialer.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "github.com/xtls/xray-core/common/net" 8 | "github.com/xtls/xray-core/transport/internet" 9 | "github.com/xtls/xray-core/transport/internet/stat" 10 | ) 11 | 12 | func init() { 13 | common.Must(internet.RegisterTransportDialer(protocolName, 14 | func(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) { 15 | var sockopt *internet.SocketConfig 16 | if streamSettings != nil { 17 | sockopt = streamSettings.SocketSettings 18 | } 19 | conn, err := internet.DialSystem(ctx, dest, sockopt) 20 | if err != nil { 21 | return nil, err 22 | } 23 | // TODO: handle dialer options 24 | return stat.Connection(conn), nil 25 | })) 26 | } 27 | -------------------------------------------------------------------------------- /common/task/periodic_test.go: -------------------------------------------------------------------------------- 1 | package task_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/xtls/xray-core/common" 8 | . "github.com/xtls/xray-core/common/task" 9 | ) 10 | 11 | func TestPeriodicTaskStop(t *testing.T) { 12 | value := 0 13 | task := &Periodic{ 14 | Interval: time.Second * 2, 15 | Execute: func() error { 16 | value++ 17 | return nil 18 | }, 19 | } 20 | common.Must(task.Start()) 21 | time.Sleep(time.Second * 5) 22 | common.Must(task.Close()) 23 | if value != 3 { 24 | t.Fatal("expected 3, but got ", value) 25 | } 26 | time.Sleep(time.Second * 4) 27 | if value != 3 { 28 | t.Fatal("expected 3, but got ", value) 29 | } 30 | common.Must(task.Start()) 31 | time.Sleep(time.Second * 3) 32 | if value != 5 { 33 | t.Fatal("Expected 5, but ", value) 34 | } 35 | common.Must(task.Close()) 36 | } 37 | -------------------------------------------------------------------------------- /proxy/shadowsocks_2022/config.go: -------------------------------------------------------------------------------- 1 | package shadowsocks_2022 2 | 3 | import ( 4 | "google.golang.org/protobuf/proto" 5 | 6 | "github.com/xtls/xray-core/common/protocol" 7 | ) 8 | 9 | // MemoryAccount is an account type converted from Account. 10 | type MemoryAccount struct { 11 | Key string 12 | } 13 | 14 | // AsAccount implements protocol.AsAccount. 15 | func (u *Account) AsAccount() (protocol.Account, error) { 16 | return &MemoryAccount{ 17 | Key: u.GetKey(), 18 | }, nil 19 | } 20 | 21 | // Equals implements protocol.Account.Equals(). 22 | func (a *MemoryAccount) Equals(another protocol.Account) bool { 23 | if account, ok := another.(*MemoryAccount); ok { 24 | return a.Key == account.Key 25 | } 26 | return false 27 | } 28 | 29 | func (a *MemoryAccount) ToProto() proto.Message { 30 | return &Account{ 31 | Key: a.Key, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /testing/scenarios/common_regular.go: -------------------------------------------------------------------------------- 1 | //go:build !coverage 2 | // +build !coverage 3 | 4 | package scenarios 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "os" 10 | "os/exec" 11 | ) 12 | 13 | func BuildXray() error { 14 | genTestBinaryPath() 15 | if _, err := os.Stat(testBinaryPath); err == nil { 16 | return nil 17 | } 18 | 19 | fmt.Printf("Building Xray into path (%s)\n", testBinaryPath) 20 | cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath()) 21 | cmd.Stdout = os.Stdout 22 | cmd.Stderr = os.Stderr 23 | return cmd.Run() 24 | } 25 | 26 | func RunXrayProtobuf(config []byte) *exec.Cmd { 27 | genTestBinaryPath() 28 | proc := exec.Command(testBinaryPath, "-config=stdin:", "-format=pb") 29 | proc.Stdin = bytes.NewBuffer(config) 30 | proc.Stderr = os.Stderr 31 | proc.Stdout = os.Stdout 32 | 33 | return proc 34 | } 35 | -------------------------------------------------------------------------------- /features/policy/default.go: -------------------------------------------------------------------------------- 1 | package policy 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // DefaultManager is the implementation of the Manager. 8 | type DefaultManager struct{} 9 | 10 | // Type implements common.HasType. 11 | func (DefaultManager) Type() interface{} { 12 | return ManagerType() 13 | } 14 | 15 | // ForLevel implements Manager. 16 | func (DefaultManager) ForLevel(level uint32) Session { 17 | p := SessionDefault() 18 | if level == 1 { 19 | p.Timeouts.ConnectionIdle = time.Second * 600 20 | } 21 | return p 22 | } 23 | 24 | // ForSystem implements Manager. 25 | func (DefaultManager) ForSystem() System { 26 | return System{} 27 | } 28 | 29 | // Start implements common.Runnable. 30 | func (DefaultManager) Start() error { 31 | return nil 32 | } 33 | 34 | // Close implements common.Closable. 35 | func (DefaultManager) Close() error { 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /app/commander/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.commander; 4 | option csharp_namespace = "Xray.App.Commander"; 5 | option go_package = "github.com/xtls/xray-core/app/commander"; 6 | option java_package = "com.xray.app.commander"; 7 | option java_multiple_files = true; 8 | 9 | import "common/serial/typed_message.proto"; 10 | 11 | // Config is the settings for Commander. 12 | message Config { 13 | // Tag of the outbound handler that handles grpc connections. 14 | string tag = 1; 15 | 16 | // Network address of commander grpc service. 17 | string listen = 3; 18 | 19 | // Services that supported by this server. All services must implement Service 20 | // interface. 21 | repeated xray.common.serial.TypedMessage service = 2; 22 | } 23 | 24 | // ReflectionConfig is the placeholder config for ReflectionService. 25 | message ReflectionConfig {} 26 | -------------------------------------------------------------------------------- /common/serial/serial.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | // ReadUint16 reads first two bytes from the reader, and then converts them to an uint16 value. 9 | func ReadUint16(reader io.Reader) (uint16, error) { 10 | var b [2]byte 11 | if _, err := io.ReadFull(reader, b[:]); err != nil { 12 | return 0, err 13 | } 14 | return binary.BigEndian.Uint16(b[:]), nil 15 | } 16 | 17 | // WriteUint16 writes an uint16 value into writer. 18 | func WriteUint16(writer io.Writer, value uint16) (int, error) { 19 | var b [2]byte 20 | binary.BigEndian.PutUint16(b[:], value) 21 | return writer.Write(b[:]) 22 | } 23 | 24 | // WriteUint64 writes an uint64 value into writer. 25 | func WriteUint64(writer io.Writer, value uint64) (int, error) { 26 | var b [8]byte 27 | binary.BigEndian.PutUint64(b[:], value) 28 | return writer.Write(b[:]) 29 | } 30 | -------------------------------------------------------------------------------- /infra/conf/cfgcommon/duration/duration.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type Duration int64 10 | 11 | // MarshalJSON implements encoding/json.Marshaler.MarshalJSON 12 | func (d *Duration) MarshalJSON() ([]byte, error) { 13 | dr := time.Duration(*d) 14 | return json.Marshal(dr.String()) 15 | } 16 | 17 | // UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON 18 | func (d *Duration) UnmarshalJSON(b []byte) error { 19 | var v interface{} 20 | if err := json.Unmarshal(b, &v); err != nil { 21 | return err 22 | } 23 | switch value := v.(type) { 24 | case string: 25 | var err error 26 | dr, err := time.ParseDuration(value) 27 | if err != nil { 28 | return err 29 | } 30 | *d = Duration(dr) 31 | return nil 32 | default: 33 | return fmt.Errorf("invalid duration: %v", v) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /transport/internet/tcp/sockopt_darwin.go: -------------------------------------------------------------------------------- 1 | //go:build darwin 2 | // +build darwin 3 | 4 | package tcp 5 | 6 | import ( 7 | "github.com/xtls/xray-core/common/errors" 8 | "github.com/xtls/xray-core/common/net" 9 | "github.com/xtls/xray-core/transport/internet" 10 | "github.com/xtls/xray-core/transport/internet/stat" 11 | ) 12 | 13 | // GetOriginalDestination from tcp conn 14 | func GetOriginalDestination(conn stat.Connection) (net.Destination, error) { 15 | la := conn.LocalAddr() 16 | ra := conn.RemoteAddr() 17 | ip, port, err := internet.OriginalDst(la, ra) 18 | if err != nil { 19 | return net.Destination{}, errors.New("failed to get destination").Base(err) 20 | } 21 | dest := net.TCPDestination(net.IPAddress(ip), net.Port(port)) 22 | if !dest.IsValid() { 23 | return net.Destination{}, errors.New("failed to parse destination.") 24 | } 25 | return dest, nil 26 | } 27 | -------------------------------------------------------------------------------- /common/bitmask/byte_test.go: -------------------------------------------------------------------------------- 1 | package bitmask_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/bitmask" 7 | ) 8 | 9 | func TestBitmaskByte(t *testing.T) { 10 | b := Byte(0) 11 | b.Set(Byte(1)) 12 | if !b.Has(1) { 13 | t.Fatal("expected ", b, " to contain 1, but actually not") 14 | } 15 | 16 | b.Set(Byte(2)) 17 | if !b.Has(2) { 18 | t.Fatal("expected ", b, " to contain 2, but actually not") 19 | } 20 | if !b.Has(1) { 21 | t.Fatal("expected ", b, " to contain 1, but actually not") 22 | } 23 | 24 | b.Clear(Byte(1)) 25 | if !b.Has(2) { 26 | t.Fatal("expected ", b, " to contain 2, but actually not") 27 | } 28 | if b.Has(1) { 29 | t.Fatal("expected ", b, " to not contain 1, but actually did") 30 | } 31 | 32 | b.Toggle(Byte(2)) 33 | if b.Has(2) { 34 | t.Fatal("expected ", b, " to not contain 2, but actually did") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /transport/internet/headers/srtp/srtp.go: -------------------------------------------------------------------------------- 1 | package srtp 2 | 3 | import ( 4 | "context" 5 | "encoding/binary" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/dice" 9 | ) 10 | 11 | type SRTP struct { 12 | header uint16 13 | number uint16 14 | } 15 | 16 | func (*SRTP) Size() int32 { 17 | return 4 18 | } 19 | 20 | // Serialize implements PacketHeader. 21 | func (s *SRTP) Serialize(b []byte) { 22 | s.number++ 23 | binary.BigEndian.PutUint16(b, s.header) 24 | binary.BigEndian.PutUint16(b[2:], s.number) 25 | } 26 | 27 | // New returns a new SRTP instance based on the given config. 28 | func New(ctx context.Context, config interface{}) (interface{}, error) { 29 | return &SRTP{ 30 | header: 0xB5E8, 31 | number: dice.RollUint16(), 32 | }, nil 33 | } 34 | 35 | func init() { 36 | common.Must(common.RegisterConfig((*Config)(nil), New)) 37 | } 38 | -------------------------------------------------------------------------------- /transport/internet/system_listener_test.go: -------------------------------------------------------------------------------- 1 | package internet_test 2 | 3 | import ( 4 | "context" 5 | "net" 6 | "syscall" 7 | "testing" 8 | 9 | "github.com/sagernet/sing/common/control" 10 | "github.com/xtls/xray-core/common" 11 | "github.com/xtls/xray-core/transport/internet" 12 | ) 13 | 14 | func TestRegisterListenerController(t *testing.T) { 15 | var gotFd uintptr 16 | 17 | common.Must(internet.RegisterListenerController(func(network, address string, conn syscall.RawConn) error { 18 | return control.Raw(conn, func(fd uintptr) error { 19 | gotFd = fd 20 | return nil 21 | }) 22 | })) 23 | 24 | conn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{ 25 | IP: net.IPv4zero, 26 | }, nil) 27 | common.Must(err) 28 | common.Must(conn.Close()) 29 | 30 | if gotFd == 0 { 31 | t.Error("expected none-zero fd, but actually 0") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /transport/internet/tcp/sockopt_freebsd.go: -------------------------------------------------------------------------------- 1 | //go:build freebsd 2 | // +build freebsd 3 | 4 | package tcp 5 | 6 | import ( 7 | "github.com/xtls/xray-core/common/errors" 8 | "github.com/xtls/xray-core/common/net" 9 | "github.com/xtls/xray-core/transport/internet" 10 | "github.com/xtls/xray-core/transport/internet/stat" 11 | ) 12 | 13 | // GetOriginalDestination from tcp conn 14 | func GetOriginalDestination(conn stat.Connection) (net.Destination, error) { 15 | la := conn.LocalAddr() 16 | ra := conn.RemoteAddr() 17 | ip, port, err := internet.OriginalDst(la, ra) 18 | if err != nil { 19 | return net.Destination{}, errors.New("failed to get destination").Base(err) 20 | } 21 | dest := net.TCPDestination(net.IPAddress(ip), net.Port(port)) 22 | if !dest.IsValid() { 23 | return net.Destination{}, errors.New("failed to parse destination.") 24 | } 25 | return dest, nil 26 | } 27 | -------------------------------------------------------------------------------- /infra/conf/lint.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import "github.com/xtls/xray-core/common/errors" 4 | 5 | type ConfigureFilePostProcessingStage interface { 6 | Process(conf *Config) error 7 | } 8 | 9 | var configureFilePostProcessingStages map[string]ConfigureFilePostProcessingStage 10 | 11 | func RegisterConfigureFilePostProcessingStage(name string, stage ConfigureFilePostProcessingStage) { 12 | if configureFilePostProcessingStages == nil { 13 | configureFilePostProcessingStages = make(map[string]ConfigureFilePostProcessingStage) 14 | } 15 | configureFilePostProcessingStages[name] = stage 16 | } 17 | 18 | func PostProcessConfigureFile(conf *Config) error { 19 | for k, v := range configureFilePostProcessingStages { 20 | if err := v.Process(conf); err != nil { 21 | return errors.New("Rejected by Postprocessing Stage ", k).AtError().Base(err) 22 | } 23 | } 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /proxy/socks/udpfilter.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "net" 5 | "sync" 6 | ) 7 | 8 | /* 9 | In the sock implementation of * ray, UDP authentication is flawed and can be bypassed. 10 | Tracking a UDP connection may be a bit troublesome. 11 | Here is a simple solution. 12 | We create a filter, add remote IP to the pool when it try to establish a UDP connection with auth. 13 | And drop UDP packets from unauthorized IP. 14 | After discussion, we believe it is not necessary to add a timeout mechanism to this filter. 15 | */ 16 | 17 | type UDPFilter struct { 18 | ips sync.Map 19 | } 20 | 21 | func (f *UDPFilter) Add(addr net.Addr) bool { 22 | ip, _, _ := net.SplitHostPort(addr.String()) 23 | f.ips.Store(ip, true) 24 | return true 25 | } 26 | 27 | func (f *UDPFilter) Check(addr net.Addr) bool { 28 | ip, _, _ := net.SplitHostPort(addr.String()) 29 | _, ok := f.ips.Load(ip) 30 | return ok 31 | } 32 | -------------------------------------------------------------------------------- /transport/internet/headers/utp/utp.go: -------------------------------------------------------------------------------- 1 | package utp 2 | 3 | import ( 4 | "context" 5 | "encoding/binary" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/dice" 9 | ) 10 | 11 | type UTP struct { 12 | header byte 13 | extension byte 14 | connectionID uint16 15 | } 16 | 17 | func (*UTP) Size() int32 { 18 | return 4 19 | } 20 | 21 | // Serialize implements PacketHeader. 22 | func (u *UTP) Serialize(b []byte) { 23 | binary.BigEndian.PutUint16(b, u.connectionID) 24 | b[2] = u.header 25 | b[3] = u.extension 26 | } 27 | 28 | // New creates a new UTP header for the given config. 29 | func New(ctx context.Context, config interface{}) (interface{}, error) { 30 | return &UTP{ 31 | header: 1, 32 | extension: 0, 33 | connectionID: dice.RollUint16(), 34 | }, nil 35 | } 36 | 37 | func init() { 38 | common.Must(common.RegisterConfig((*Config)(nil), New)) 39 | } 40 | -------------------------------------------------------------------------------- /common/buf/readv_windows.go: -------------------------------------------------------------------------------- 1 | package buf 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | type windowsReader struct { 8 | bufs []syscall.WSABuf 9 | } 10 | 11 | func (r *windowsReader) Init(bs []*Buffer) { 12 | if r.bufs == nil { 13 | r.bufs = make([]syscall.WSABuf, 0, len(bs)) 14 | } 15 | for _, b := range bs { 16 | r.bufs = append(r.bufs, syscall.WSABuf{Len: uint32(Size), Buf: &b.v[0]}) 17 | } 18 | } 19 | 20 | func (r *windowsReader) Clear() { 21 | for idx := range r.bufs { 22 | r.bufs[idx].Buf = nil 23 | } 24 | r.bufs = r.bufs[:0] 25 | } 26 | 27 | func (r *windowsReader) Read(fd uintptr) int32 { 28 | var nBytes uint32 29 | var flags uint32 30 | err := syscall.WSARecv(syscall.Handle(fd), &r.bufs[0], uint32(len(r.bufs)), &nBytes, &flags, nil, nil) 31 | if err != nil { 32 | return -1 33 | } 34 | return int32(nBytes) 35 | } 36 | 37 | func newMultiReader() multiReader { 38 | return new(windowsReader) 39 | } 40 | -------------------------------------------------------------------------------- /main/commands/all/api/api.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "github.com/xtls/xray-core/main/commands/base" 5 | ) 6 | 7 | // CmdAPI calls an API in an Xray process 8 | var CmdAPI = &base.Command{ 9 | UsageLine: "{{.Exec}} api", 10 | Short: "Call an API in an Xray process", 11 | Long: `{{.Exec}} {{.LongName}} provides tools to manipulate Xray via its API. 12 | `, 13 | Commands: []*base.Command{ 14 | cmdRestartLogger, 15 | cmdGetStats, 16 | cmdQueryStats, 17 | cmdSysStats, 18 | cmdBalancerInfo, 19 | cmdBalancerOverride, 20 | cmdAddInbounds, 21 | cmdAddOutbounds, 22 | cmdRemoveInbounds, 23 | cmdRemoveOutbounds, 24 | cmdListInbounds, 25 | cmdListOutbounds, 26 | cmdAddInboundUsers, 27 | cmdRemoveInboundUsers, 28 | cmdInboundUser, 29 | cmdInboundUserCount, 30 | cmdAddRules, 31 | cmdRemoveRules, 32 | cmdSourceIpBlock, 33 | cmdOnlineStats, 34 | cmdOnlineStatsIpList, 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /proxy/http/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.http; 4 | option csharp_namespace = "Xray.Proxy.Http"; 5 | option go_package = "github.com/xtls/xray-core/proxy/http"; 6 | option java_package = "com.xray.proxy.http"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | 11 | message Account { 12 | string username = 1; 13 | string password = 2; 14 | } 15 | 16 | // Config for HTTP proxy server. 17 | message ServerConfig { 18 | map accounts = 2; 19 | bool allow_transparent = 3; 20 | uint32 user_level = 4; 21 | } 22 | 23 | message Header { 24 | string key = 1; 25 | string value = 2; 26 | } 27 | 28 | // ClientConfig is the protobuf config for HTTP proxy client. 29 | message ClientConfig { 30 | // Sever is a list of HTTP server addresses. 31 | xray.common.protocol.ServerEndpoint server = 1; 32 | repeated Header header = 2; 33 | } 34 | -------------------------------------------------------------------------------- /common/buf/override.go: -------------------------------------------------------------------------------- 1 | package buf 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/net" 5 | ) 6 | 7 | type EndpointOverrideReader struct { 8 | Reader 9 | Dest net.Address 10 | OriginalDest net.Address 11 | } 12 | 13 | func (r *EndpointOverrideReader) ReadMultiBuffer() (MultiBuffer, error) { 14 | mb, err := r.Reader.ReadMultiBuffer() 15 | if err == nil { 16 | for _, b := range mb { 17 | if b.UDP != nil && b.UDP.Address == r.OriginalDest { 18 | b.UDP.Address = r.Dest 19 | } 20 | } 21 | } 22 | return mb, err 23 | } 24 | 25 | type EndpointOverrideWriter struct { 26 | Writer 27 | Dest net.Address 28 | OriginalDest net.Address 29 | } 30 | 31 | func (w *EndpointOverrideWriter) WriteMultiBuffer(mb MultiBuffer) error { 32 | for _, b := range mb { 33 | if b.UDP != nil && b.UDP.Address == w.Dest { 34 | b.UDP.Address = w.OriginalDest 35 | } 36 | } 37 | return w.Writer.WriteMultiBuffer(mb) 38 | } 39 | -------------------------------------------------------------------------------- /infra/conf/dokodemo_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | . "github.com/xtls/xray-core/infra/conf" 8 | "github.com/xtls/xray-core/proxy/dokodemo" 9 | ) 10 | 11 | func TestDokodemoConfig(t *testing.T) { 12 | creator := func() Buildable { 13 | return new(DokodemoConfig) 14 | } 15 | 16 | runMultiTestCase(t, []TestCase{ 17 | { 18 | Input: `{ 19 | "address": "8.8.8.8", 20 | "port": 53, 21 | "network": "tcp", 22 | "followRedirect": true, 23 | "userLevel": 1 24 | }`, 25 | Parser: loadJSON(creator), 26 | Output: &dokodemo.Config{ 27 | Address: &net.IPOrDomain{ 28 | Address: &net.IPOrDomain_Ip{ 29 | Ip: []byte{8, 8, 8, 8}, 30 | }, 31 | }, 32 | Port: 53, 33 | Networks: []net.Network{net.Network_TCP}, 34 | FollowRedirect: true, 35 | UserLevel: 1, 36 | }, 37 | }, 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /main/commands/all/x25519.go: -------------------------------------------------------------------------------- 1 | package all 2 | 3 | import ( 4 | "github.com/xtls/xray-core/main/commands/base" 5 | ) 6 | 7 | var cmdX25519 = &base.Command{ 8 | UsageLine: `{{.Exec}} x25519 [-i "private key (base64.RawURLEncoding)"] [--std-encoding]`, 9 | Short: `Generate key pair for X25519 key exchange (REALITY, VLESS Encryption)`, 10 | Long: ` 11 | Generate key pair for X25519 key exchange (REALITY, VLESS Encryption). 12 | 13 | Random: {{.Exec}} x25519 14 | 15 | From private key: {{.Exec}} x25519 -i "private key (base64.RawURLEncoding)" 16 | For Std Encoding: {{.Exec}} x25519 --std-encoding 17 | `, 18 | } 19 | 20 | func init() { 21 | cmdX25519.Run = executeX25519 // break init loop 22 | } 23 | 24 | var input_stdEncoding = cmdX25519.Flag.Bool("std-encoding", false, "") 25 | var input_x25519 = cmdX25519.Flag.String("i", "", "") 26 | 27 | func executeX25519(cmd *base.Command, args []string) { 28 | Curve25519Genkey(false, *input_x25519) 29 | } 30 | -------------------------------------------------------------------------------- /transport/internet/tcp/sockopt_linux_test.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package tcp_test 5 | 6 | import ( 7 | "context" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/xtls/xray-core/common" 12 | "github.com/xtls/xray-core/testing/servers/tcp" 13 | "github.com/xtls/xray-core/transport/internet" 14 | . "github.com/xtls/xray-core/transport/internet/tcp" 15 | ) 16 | 17 | func TestGetOriginalDestination(t *testing.T) { 18 | tcpServer := tcp.Server{} 19 | dest, err := tcpServer.Start() 20 | common.Must(err) 21 | defer tcpServer.Close() 22 | 23 | config, err := internet.ToMemoryStreamConfig(nil) 24 | common.Must(err) 25 | conn, err := Dial(context.Background(), dest, config) 26 | common.Must(err) 27 | defer conn.Close() 28 | 29 | originalDest, err := GetOriginalDestination(conn) 30 | if !(dest == originalDest || strings.Contains(err.Error(), "failed to call getsockopt")) { 31 | t.Error("unexpected state") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /common/xudp/xudp_test.go: -------------------------------------------------------------------------------- 1 | package xudp 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "github.com/xtls/xray-core/common/buf" 8 | "github.com/xtls/xray-core/common/net" 9 | ) 10 | 11 | func TestXudpReadWrite(t *testing.T) { 12 | addr, _ := net.ParseDestination("tcp:127.0.0.1:1345") 13 | mb := make(buf.MultiBuffer, 0, 16) 14 | m := buf.MultiBufferContainer{ 15 | MultiBuffer: mb, 16 | } 17 | var arr [8]byte 18 | writer := NewPacketWriter(&m, addr, arr) 19 | 20 | source := make(buf.MultiBuffer, 0, 16) 21 | b := buf.New() 22 | b.WriteByte('a') 23 | b.UDP = &addr 24 | source = append(source, b) 25 | writer.WriteMultiBuffer(source) 26 | 27 | reader := NewPacketReader(&m) 28 | dest, err := reader.ReadMultiBuffer() 29 | common.Must(err) 30 | if dest[0].Byte(0) != 'a' { 31 | t.Error("failed to parse xudp buffer") 32 | } 33 | if dest[0].UDP.Port != 1345 { 34 | t.Error("failed to parse xudp buffer") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /proxy/wireguard/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.wireguard; 4 | option csharp_namespace = "Xray.Proxy.WireGuard"; 5 | option go_package = "github.com/xtls/xray-core/proxy/wireguard"; 6 | option java_package = "com.xray.proxy.wireguard"; 7 | option java_multiple_files = true; 8 | 9 | message PeerConfig { 10 | string public_key = 1; 11 | string pre_shared_key = 2; 12 | string endpoint = 3; 13 | uint32 keep_alive = 4; 14 | repeated string allowed_ips = 5; 15 | } 16 | 17 | message DeviceConfig { 18 | enum DomainStrategy { 19 | FORCE_IP = 0; 20 | FORCE_IP4 = 1; 21 | FORCE_IP6 = 2; 22 | FORCE_IP46 = 3; 23 | FORCE_IP64 = 4; 24 | } 25 | string secret_key = 1; 26 | repeated string endpoint = 2; 27 | repeated PeerConfig peers = 3; 28 | int32 mtu = 4; 29 | int32 num_workers = 5; 30 | bytes reserved = 6; 31 | DomainStrategy domain_strategy = 7; 32 | bool is_client = 8; 33 | bool no_kernel_tun = 9; 34 | } -------------------------------------------------------------------------------- /transport/internet/headers/http/resp.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | var resp400 = &ResponseConfig{ 4 | Version: &Version{ 5 | Value: "1.1", 6 | }, 7 | Status: &Status{ 8 | Code: "400", 9 | Reason: "Bad Request", 10 | }, 11 | Header: []*Header{ 12 | { 13 | Name: "Connection", 14 | Value: []string{"close"}, 15 | }, 16 | { 17 | Name: "Cache-Control", 18 | Value: []string{"private"}, 19 | }, 20 | { 21 | Name: "Content-Length", 22 | Value: []string{"0"}, 23 | }, 24 | }, 25 | } 26 | 27 | var resp404 = &ResponseConfig{ 28 | Version: &Version{ 29 | Value: "1.1", 30 | }, 31 | Status: &Status{ 32 | Code: "404", 33 | Reason: "Not Found", 34 | }, 35 | Header: []*Header{ 36 | { 37 | Name: "Connection", 38 | Value: []string{"close"}, 39 | }, 40 | { 41 | Name: "Cache-Control", 42 | Value: []string{"private"}, 43 | }, 44 | { 45 | Name: "Content-Length", 46 | Value: []string{"0"}, 47 | }, 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /common/dice/dice_test.go: -------------------------------------------------------------------------------- 1 | package dice_test 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | 7 | . "github.com/xtls/xray-core/common/dice" 8 | ) 9 | 10 | func BenchmarkRoll1(b *testing.B) { 11 | for i := 0; i < b.N; i++ { 12 | Roll(1) 13 | } 14 | } 15 | 16 | func BenchmarkRoll20(b *testing.B) { 17 | for i := 0; i < b.N; i++ { 18 | Roll(20) 19 | } 20 | } 21 | 22 | func BenchmarkIntn1(b *testing.B) { 23 | for i := 0; i < b.N; i++ { 24 | rand.Intn(1) 25 | } 26 | } 27 | 28 | func BenchmarkIntn20(b *testing.B) { 29 | for i := 0; i < b.N; i++ { 30 | rand.Intn(20) 31 | } 32 | } 33 | 34 | func BenchmarkInt63(b *testing.B) { 35 | for i := 0; i < b.N; i++ { 36 | _ = uint16(rand.Int63() >> 47) 37 | } 38 | } 39 | 40 | func BenchmarkInt31(b *testing.B) { 41 | for i := 0; i < b.N; i++ { 42 | _ = uint16(rand.Int31() >> 15) 43 | } 44 | } 45 | 46 | func BenchmarkIntn(b *testing.B) { 47 | for i := 0; i < b.N; i++ { 48 | _ = uint16(rand.Intn(65536)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /common/log/logger_test.go: -------------------------------------------------------------------------------- 1 | package log_test 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | "testing" 7 | "time" 8 | 9 | "github.com/xtls/xray-core/common" 10 | "github.com/xtls/xray-core/common/buf" 11 | . "github.com/xtls/xray-core/common/log" 12 | ) 13 | 14 | func TestFileLogger(t *testing.T) { 15 | f, err := os.CreateTemp("", "vtest") 16 | common.Must(err) 17 | path := f.Name() 18 | common.Must(f.Close()) 19 | defer os.Remove(path) 20 | 21 | creator, err := CreateFileLogWriter(path) 22 | common.Must(err) 23 | 24 | handler := NewLogger(creator) 25 | handler.Handle(&GeneralMessage{Content: "Test Log"}) 26 | time.Sleep(2 * time.Second) 27 | 28 | common.Must(common.Close(handler)) 29 | 30 | f, err = os.Open(path) 31 | common.Must(err) 32 | defer f.Close() 33 | 34 | b, err := buf.ReadAllToBytes(f) 35 | common.Must(err) 36 | if !strings.Contains(string(b), "Test Log") { 37 | t.Fatal("Expect log text contains 'Test Log', but actually: ", string(b)) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /main/commands/all/uuid.go: -------------------------------------------------------------------------------- 1 | package all 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/xtls/xray-core/common/uuid" 7 | "github.com/xtls/xray-core/main/commands/base" 8 | ) 9 | 10 | var cmdUUID = &base.Command{ 11 | UsageLine: `{{.Exec}} uuid [-i "example"]`, 12 | Short: `Generate UUIDv4 or UUIDv5 (VLESS)`, 13 | Long: ` 14 | Generate UUIDv4 or UUIDv5 (VLESS). 15 | 16 | UUIDv4 (random): {{.Exec}} uuid 17 | 18 | UUIDv5 (from input): {{.Exec}} uuid -i "example" 19 | `, 20 | } 21 | 22 | func init() { 23 | cmdUUID.Run = executeUUID // break init loop 24 | } 25 | 26 | var input = cmdUUID.Flag.String("i", "", "") 27 | 28 | func executeUUID(cmd *base.Command, args []string) { 29 | var output string 30 | if l := len(*input); l == 0 { 31 | u := uuid.New() 32 | output = u.String() 33 | } else if l <= 30 { 34 | u, _ := uuid.ParseString(*input) 35 | output = u.String() 36 | } else { 37 | output = "Input must be within 30 bytes." 38 | } 39 | fmt.Println(output) 40 | } 41 | -------------------------------------------------------------------------------- /proxy/shadowsocks/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.shadowsocks; 4 | option csharp_namespace = "Xray.Proxy.Shadowsocks"; 5 | option go_package = "github.com/xtls/xray-core/proxy/shadowsocks"; 6 | option java_package = "com.xray.proxy.shadowsocks"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/network.proto"; 10 | import "common/protocol/user.proto"; 11 | import "common/protocol/server_spec.proto"; 12 | 13 | message Account { 14 | string password = 1; 15 | CipherType cipher_type = 2; 16 | 17 | bool iv_check = 3; 18 | } 19 | 20 | enum CipherType { 21 | UNKNOWN = 0; 22 | AES_128_GCM = 5; 23 | AES_256_GCM = 6; 24 | CHACHA20_POLY1305 = 7; 25 | XCHACHA20_POLY1305 = 8; 26 | NONE = 9; 27 | } 28 | 29 | message ServerConfig { 30 | repeated xray.common.protocol.User users = 1; 31 | repeated xray.common.net.Network network = 2; 32 | } 33 | 34 | message ClientConfig { 35 | xray.common.protocol.ServerEndpoint server = 1; 36 | } 37 | -------------------------------------------------------------------------------- /common/type_test.go: -------------------------------------------------------------------------------- 1 | package common_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | . "github.com/xtls/xray-core/common" 8 | ) 9 | 10 | type TConfig struct { 11 | value int 12 | } 13 | 14 | type YConfig struct { 15 | value string 16 | } 17 | 18 | func TestObjectCreation(t *testing.T) { 19 | f := func(ctx context.Context, t interface{}) (interface{}, error) { 20 | return func() int { 21 | return t.(*TConfig).value 22 | }, nil 23 | } 24 | 25 | Must(RegisterConfig((*TConfig)(nil), f)) 26 | err := RegisterConfig((*TConfig)(nil), f) 27 | if err == nil { 28 | t.Error("expect non-nil error, but got nil") 29 | } 30 | 31 | g, err := CreateObject(context.Background(), &TConfig{value: 2}) 32 | Must(err) 33 | if v := g.(func() int)(); v != 2 { 34 | t.Error("expect return value 2, but got ", v) 35 | } 36 | 37 | _, err = CreateObject(context.Background(), &YConfig{value: "T"}) 38 | if err == nil { 39 | t.Error("expect non-nil error, but got nil") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /transport/internet/kcp/connection_test.go: -------------------------------------------------------------------------------- 1 | package kcp_test 2 | 3 | import ( 4 | "io" 5 | "testing" 6 | "time" 7 | 8 | "github.com/xtls/xray-core/common/buf" 9 | . "github.com/xtls/xray-core/transport/internet/kcp" 10 | ) 11 | 12 | type NoOpCloser int 13 | 14 | func (NoOpCloser) Close() error { 15 | return nil 16 | } 17 | 18 | func TestConnectionReadTimeout(t *testing.T) { 19 | conn := NewConnection(ConnMetadata{Conversation: 1}, &KCPPacketWriter{ 20 | Writer: buf.DiscardBytes, 21 | }, NoOpCloser(0), &Config{}) 22 | conn.SetReadDeadline(time.Now().Add(time.Second)) 23 | 24 | b := make([]byte, 1024) 25 | nBytes, err := conn.Read(b) 26 | if nBytes != 0 || err == nil { 27 | t.Error("unexpected read: ", nBytes, err) 28 | } 29 | 30 | conn.Terminate() 31 | } 32 | 33 | func TestConnectionInterface(t *testing.T) { 34 | _ = (io.Writer)(new(Connection)) 35 | _ = (io.Reader)(new(Connection)) 36 | _ = (buf.Reader)(new(Connection)) 37 | _ = (buf.Writer)(new(Connection)) 38 | } 39 | -------------------------------------------------------------------------------- /transport/internet/kcp/xor_amd64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | 3 | // func xorfwd(x []byte) 4 | TEXT ·xorfwd(SB),NOSPLIT,$0 5 | MOVQ x+0(FP), SI // x[i] 6 | MOVQ x_len+8(FP), CX // x.len 7 | MOVQ x+0(FP), DI 8 | ADDQ $4, DI // x[i+4] 9 | SUBQ $4, CX 10 | xorfwdloop: 11 | MOVL (SI), AX 12 | XORL AX, (DI) 13 | ADDQ $4, SI 14 | ADDQ $4, DI 15 | SUBQ $4, CX 16 | 17 | CMPL CX, $0 18 | JE xorfwddone 19 | 20 | JMP xorfwdloop 21 | xorfwddone: 22 | RET 23 | 24 | // func xorbkd(x []byte) 25 | TEXT ·xorbkd(SB),NOSPLIT,$0 26 | MOVQ x+0(FP), SI 27 | MOVQ x_len+8(FP), CX // x.len 28 | MOVQ x+0(FP), DI 29 | ADDQ CX, SI // x[-8] 30 | SUBQ $8, SI 31 | ADDQ CX, DI // x[-4] 32 | SUBQ $4, DI 33 | SUBQ $4, CX 34 | xorbkdloop: 35 | MOVL (SI), AX 36 | XORL AX, (DI) 37 | SUBQ $4, SI 38 | SUBQ $4, DI 39 | SUBQ $4, CX 40 | 41 | CMPL CX, $0 42 | JE xorbkddone 43 | 44 | JMP xorbkdloop 45 | 46 | xorbkddone: 47 | RET 48 | -------------------------------------------------------------------------------- /transport/internet/kcp/crypt_test.go: -------------------------------------------------------------------------------- 1 | package kcp_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | "github.com/xtls/xray-core/common" 8 | . "github.com/xtls/xray-core/transport/internet/kcp" 9 | ) 10 | 11 | func TestSimpleAuthenticator(t *testing.T) { 12 | cache := make([]byte, 512) 13 | 14 | payload := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'} 15 | 16 | auth := NewSimpleAuthenticator() 17 | b := auth.Seal(cache[:0], nil, payload, nil) 18 | c, err := auth.Open(cache[:0], nil, b, nil) 19 | common.Must(err) 20 | if r := cmp.Diff(c, payload); r != "" { 21 | t.Error(r) 22 | } 23 | } 24 | 25 | func TestSimpleAuthenticator2(t *testing.T) { 26 | cache := make([]byte, 512) 27 | 28 | payload := []byte{'a', 'b'} 29 | 30 | auth := NewSimpleAuthenticator() 31 | b := auth.Seal(cache[:0], nil, payload, nil) 32 | c, err := auth.Open(cache[:0], nil, b, nil) 33 | common.Must(err) 34 | if r := cmp.Diff(c, payload); r != "" { 35 | t.Error(r) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/errors/multi_error.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | type multiError []error 9 | 10 | func (e multiError) Error() string { 11 | var r strings.Builder 12 | r.WriteString("multierr: ") 13 | for _, err := range e { 14 | r.WriteString(err.Error()) 15 | r.WriteString(" | ") 16 | } 17 | return r.String() 18 | } 19 | 20 | func Combine(maybeError ...error) error { 21 | var errs multiError 22 | for _, err := range maybeError { 23 | if err != nil { 24 | errs = append(errs, err) 25 | } 26 | } 27 | if len(errs) == 0 { 28 | return nil 29 | } 30 | return errs 31 | } 32 | 33 | func AllEqual(expected error, actual error) bool { 34 | switch errs := actual.(type) { 35 | case multiError: 36 | if len(errs) == 0 { 37 | return false 38 | } 39 | for _, err := range errs { 40 | if !errors.Is(err, expected) { 41 | return false 42 | } 43 | } 44 | return true 45 | default: 46 | return errors.Is(errs, expected) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /testing/servers/http/http.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | ) 8 | 9 | type Server struct { 10 | Port net.Port 11 | PathHandler map[string]http.HandlerFunc 12 | server *http.Server 13 | } 14 | 15 | func (s *Server) ServeHTTP(resp http.ResponseWriter, req *http.Request) { 16 | if req.URL.Path == "/" { 17 | resp.Header().Set("Content-Type", "text/plain; charset=utf-8") 18 | resp.WriteHeader(http.StatusOK) 19 | resp.Write([]byte("Home")) 20 | return 21 | } 22 | 23 | handler, found := s.PathHandler[req.URL.Path] 24 | if found { 25 | handler(resp, req) 26 | } 27 | } 28 | 29 | func (s *Server) Start() (net.Destination, error) { 30 | s.server = &http.Server{ 31 | Addr: "127.0.0.1:" + s.Port.String(), 32 | Handler: s, 33 | } 34 | go s.server.ListenAndServe() 35 | return net.TCPDestination(net.LocalHostIP, s.Port), nil 36 | } 37 | 38 | func (s *Server) Close() error { 39 | return s.server.Close() 40 | } 41 | -------------------------------------------------------------------------------- /common/common_test.go: -------------------------------------------------------------------------------- 1 | package common_test 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | . "github.com/xtls/xray-core/common" 8 | ) 9 | 10 | func TestMust(t *testing.T) { 11 | hasPanic := func(f func()) (ret bool) { 12 | defer func() { 13 | if r := recover(); r != nil { 14 | ret = true 15 | } 16 | }() 17 | f() 18 | return false 19 | } 20 | 21 | testCases := []struct { 22 | Input func() 23 | Panic bool 24 | }{ 25 | { 26 | Panic: true, 27 | Input: func() { Must(func() error { return errors.New("test error") }()) }, 28 | }, 29 | { 30 | Panic: true, 31 | Input: func() { Must2(func() (int, error) { return 0, errors.New("test error") }()) }, 32 | }, 33 | { 34 | Panic: false, 35 | Input: func() { Must(func() error { return nil }()) }, 36 | }, 37 | } 38 | 39 | for idx, test := range testCases { 40 | if hasPanic(test.Input) != test.Panic { 41 | t.Error("test case #", idx, " expect panic ", test.Panic, " but actually not") 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /infra/conf/shadowsocks_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | "github.com/xtls/xray-core/common/protocol" 8 | "github.com/xtls/xray-core/common/serial" 9 | . "github.com/xtls/xray-core/infra/conf" 10 | "github.com/xtls/xray-core/proxy/shadowsocks" 11 | ) 12 | 13 | func TestShadowsocksServerConfigParsing(t *testing.T) { 14 | creator := func() Buildable { 15 | return new(ShadowsocksServerConfig) 16 | } 17 | 18 | runMultiTestCase(t, []TestCase{ 19 | { 20 | Input: `{ 21 | "method": "aes-256-GCM", 22 | "password": "xray-password" 23 | }`, 24 | Parser: loadJSON(creator), 25 | Output: &shadowsocks.ServerConfig{ 26 | Users: []*protocol.User{{ 27 | Account: serial.ToTypedMessage(&shadowsocks.Account{ 28 | CipherType: shadowsocks.CipherType_AES_256_GCM, 29 | Password: "xray-password", 30 | }), 31 | }}, 32 | Network: []net.Network{net.Network_TCP}, 33 | }, 34 | }, 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /transport/internet/headers/noop/noop.go: -------------------------------------------------------------------------------- 1 | package noop 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/xtls/xray-core/common" 8 | ) 9 | 10 | type NoOpHeader struct{} 11 | 12 | func (NoOpHeader) Size() int32 { 13 | return 0 14 | } 15 | 16 | // Serialize implements PacketHeader. 17 | func (NoOpHeader) Serialize([]byte) {} 18 | 19 | func NewNoOpHeader(context.Context, interface{}) (interface{}, error) { 20 | return NoOpHeader{}, nil 21 | } 22 | 23 | type NoOpConnectionHeader struct{} 24 | 25 | func (NoOpConnectionHeader) Client(conn net.Conn) net.Conn { 26 | return conn 27 | } 28 | 29 | func (NoOpConnectionHeader) Server(conn net.Conn) net.Conn { 30 | return conn 31 | } 32 | 33 | func NewNoOpConnectionHeader(context.Context, interface{}) (interface{}, error) { 34 | return NoOpConnectionHeader{}, nil 35 | } 36 | 37 | func init() { 38 | common.Must(common.RegisterConfig((*Config)(nil), NewNoOpHeader)) 39 | common.Must(common.RegisterConfig((*ConnectionConfig)(nil), NewNoOpConnectionHeader)) 40 | } 41 | -------------------------------------------------------------------------------- /transport/internet/headers/wechat/wechat.go: -------------------------------------------------------------------------------- 1 | package wechat 2 | 3 | import ( 4 | "context" 5 | "encoding/binary" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/dice" 9 | ) 10 | 11 | type VideoChat struct { 12 | sn uint32 13 | } 14 | 15 | func (vc *VideoChat) Size() int32 { 16 | return 13 17 | } 18 | 19 | // Serialize implements PacketHeader. 20 | func (vc *VideoChat) Serialize(b []byte) { 21 | vc.sn++ 22 | b[0] = 0xa1 23 | b[1] = 0x08 24 | binary.BigEndian.PutUint32(b[2:], vc.sn) // b[2:6] 25 | b[6] = 0x00 26 | b[7] = 0x10 27 | b[8] = 0x11 28 | b[9] = 0x18 29 | b[10] = 0x30 30 | b[11] = 0x22 31 | b[12] = 0x30 32 | } 33 | 34 | // NewVideoChat returns a new VideoChat instance based on given config. 35 | func NewVideoChat(ctx context.Context, config interface{}) (interface{}, error) { 36 | return &VideoChat{ 37 | sn: uint32(dice.RollUint16()), 38 | }, nil 39 | } 40 | 41 | func init() { 42 | common.Must(common.RegisterConfig((*VideoConfig)(nil), NewVideoChat)) 43 | } 44 | -------------------------------------------------------------------------------- /app/dispatcher/stats_test.go: -------------------------------------------------------------------------------- 1 | package dispatcher_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/app/dispatcher" 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/buf" 9 | ) 10 | 11 | type TestCounter int64 12 | 13 | func (c *TestCounter) Value() int64 { 14 | return int64(*c) 15 | } 16 | 17 | func (c *TestCounter) Add(v int64) int64 { 18 | x := int64(*c) + v 19 | *c = TestCounter(x) 20 | return x 21 | } 22 | 23 | func (c *TestCounter) Set(v int64) int64 { 24 | *c = TestCounter(v) 25 | return v 26 | } 27 | 28 | func TestStatsWriter(t *testing.T) { 29 | var c TestCounter 30 | writer := &SizeStatWriter{ 31 | Counter: &c, 32 | Writer: buf.Discard, 33 | } 34 | 35 | mb := buf.MergeBytes(nil, []byte("abcd")) 36 | common.Must(writer.WriteMultiBuffer(mb)) 37 | 38 | mb = buf.MergeBytes(nil, []byte("efg")) 39 | common.Must(writer.WriteMultiBuffer(mb)) 40 | 41 | if c.Value() != 7 { 42 | t.Fatal("unexpected counter value. want 7, but got ", c.Value()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /infra/conf/reverse_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/app/reverse" 7 | "github.com/xtls/xray-core/infra/conf" 8 | ) 9 | 10 | func TestReverseConfig(t *testing.T) { 11 | creator := func() conf.Buildable { 12 | return new(conf.ReverseConfig) 13 | } 14 | 15 | runMultiTestCase(t, []TestCase{ 16 | { 17 | Input: `{ 18 | "bridges": [{ 19 | "tag": "test", 20 | "domain": "test.example.com" 21 | }] 22 | }`, 23 | Parser: loadJSON(creator), 24 | Output: &reverse.Config{ 25 | BridgeConfig: []*reverse.BridgeConfig{ 26 | {Tag: "test", Domain: "test.example.com"}, 27 | }, 28 | }, 29 | }, 30 | { 31 | Input: `{ 32 | "portals": [{ 33 | "tag": "test", 34 | "domain": "test.example.com" 35 | }] 36 | }`, 37 | Parser: loadJSON(creator), 38 | Output: &reverse.Config{ 39 | PortalConfig: []*reverse.PortalConfig{ 40 | {Tag: "test", Domain: "test.example.com"}, 41 | }, 42 | }, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /infra/conf/general_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/common" 8 | . "github.com/xtls/xray-core/infra/conf" 9 | "google.golang.org/protobuf/proto" 10 | ) 11 | 12 | func loadJSON(creator func() Buildable) func(string) (proto.Message, error) { 13 | return func(s string) (proto.Message, error) { 14 | instance := creator() 15 | if err := json.Unmarshal([]byte(s), instance); err != nil { 16 | return nil, err 17 | } 18 | return instance.Build() 19 | } 20 | } 21 | 22 | type TestCase struct { 23 | Input string 24 | Parser func(string) (proto.Message, error) 25 | Output proto.Message 26 | } 27 | 28 | func runMultiTestCase(t *testing.T, testCases []TestCase) { 29 | for _, testCase := range testCases { 30 | actual, err := testCase.Parser(testCase.Input) 31 | common.Must(err) 32 | if !proto.Equal(actual, testCase.Output) { 33 | t.Fatalf("Failed in test case:\n%s\nActual:\n%v\nExpected:\n%v", testCase.Input, actual, testCase.Output) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/buf/readv_posix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows && !wasm && !illumos 2 | // +build !windows,!wasm,!illumos 3 | 4 | package buf 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | type posixReader struct { 12 | iovecs []syscall.Iovec 13 | } 14 | 15 | func (r *posixReader) Init(bs []*Buffer) { 16 | iovecs := r.iovecs 17 | if iovecs == nil { 18 | iovecs = make([]syscall.Iovec, 0, len(bs)) 19 | } 20 | for idx, b := range bs { 21 | iovecs = append(iovecs, syscall.Iovec{ 22 | Base: &(b.v[0]), 23 | }) 24 | iovecs[idx].SetLen(int(Size)) 25 | } 26 | r.iovecs = iovecs 27 | } 28 | 29 | func (r *posixReader) Read(fd uintptr) int32 { 30 | n, _, e := syscall.Syscall(syscall.SYS_READV, fd, uintptr(unsafe.Pointer(&r.iovecs[0])), uintptr(len(r.iovecs))) 31 | if e != 0 { 32 | return -1 33 | } 34 | return int32(n) 35 | } 36 | 37 | func (r *posixReader) Clear() { 38 | for idx := range r.iovecs { 39 | r.iovecs[idx].Base = nil 40 | } 41 | r.iovecs = r.iovecs[:0] 42 | } 43 | 44 | func newMultiReader() multiReader { 45 | return &posixReader{} 46 | } 47 | -------------------------------------------------------------------------------- /common/signal/done/done.go: -------------------------------------------------------------------------------- 1 | package done 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | // Instance is a utility for notifications of something being done. 8 | type Instance struct { 9 | access sync.Mutex 10 | c chan struct{} 11 | closed bool 12 | } 13 | 14 | // New returns a new Done. 15 | func New() *Instance { 16 | return &Instance{ 17 | c: make(chan struct{}), 18 | } 19 | } 20 | 21 | // Done returns true if Close() is called. 22 | func (d *Instance) Done() bool { 23 | select { 24 | case <-d.Wait(): 25 | return true 26 | default: 27 | return false 28 | } 29 | } 30 | 31 | // Wait returns a channel for waiting for done. 32 | func (d *Instance) Wait() <-chan struct{} { 33 | return d.c 34 | } 35 | 36 | // Close marks this Done 'done'. This method may be called multiple times. All calls after first call will have no effect on its status. 37 | func (d *Instance) Close() error { 38 | d.access.Lock() 39 | defer d.access.Unlock() 40 | 41 | if d.closed { 42 | return nil 43 | } 44 | 45 | d.closed = true 46 | close(d.c) 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /transport/internet/sockopt_test.go: -------------------------------------------------------------------------------- 1 | package internet_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/common/buf" 10 | "github.com/xtls/xray-core/testing/servers/tcp" 11 | . "github.com/xtls/xray-core/transport/internet" 12 | ) 13 | 14 | func TestTCPFastOpen(t *testing.T) { 15 | tcpServer := tcp.Server{ 16 | MsgProcessor: func(b []byte) []byte { 17 | return b 18 | }, 19 | } 20 | dest, err := tcpServer.StartContext(context.Background(), &SocketConfig{Tfo: 256}) 21 | common.Must(err) 22 | defer tcpServer.Close() 23 | 24 | ctx := context.Background() 25 | dialer := DefaultSystemDialer{} 26 | conn, err := dialer.Dial(ctx, nil, dest, &SocketConfig{ 27 | Tfo: 1, 28 | }) 29 | common.Must(err) 30 | defer conn.Close() 31 | 32 | _, err = conn.Write([]byte("abcd")) 33 | common.Must(err) 34 | 35 | b := buf.New() 36 | common.Must2(b.ReadFrom(conn)) 37 | if r := cmp.Diff(b.Bytes(), []byte("abcd")); r != "" { 38 | t.Fatal(r) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/log/command/command_test.go: -------------------------------------------------------------------------------- 1 | package command_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/app/dispatcher" 8 | "github.com/xtls/xray-core/app/log" 9 | . "github.com/xtls/xray-core/app/log/command" 10 | "github.com/xtls/xray-core/app/proxyman" 11 | _ "github.com/xtls/xray-core/app/proxyman/inbound" 12 | _ "github.com/xtls/xray-core/app/proxyman/outbound" 13 | "github.com/xtls/xray-core/common" 14 | "github.com/xtls/xray-core/common/serial" 15 | "github.com/xtls/xray-core/core" 16 | ) 17 | 18 | func TestLoggerRestart(t *testing.T) { 19 | v, err := core.New(&core.Config{ 20 | App: []*serial.TypedMessage{ 21 | serial.ToTypedMessage(&log.Config{}), 22 | serial.ToTypedMessage(&dispatcher.Config{}), 23 | serial.ToTypedMessage(&proxyman.InboundConfig{}), 24 | serial.ToTypedMessage(&proxyman.OutboundConfig{}), 25 | }, 26 | }) 27 | common.Must(err) 28 | common.Must(v.Start()) 29 | 30 | server := &LoggerServer{ 31 | V: v, 32 | } 33 | common.Must2(server.RestartLogger(context.Background(), &RestartLoggerRequest{})) 34 | } 35 | -------------------------------------------------------------------------------- /proxy/shadowsocks/config_test.go: -------------------------------------------------------------------------------- 1 | package shadowsocks_test 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/common/buf" 10 | "github.com/xtls/xray-core/proxy/shadowsocks" 11 | ) 12 | 13 | func TestAEADCipherUDP(t *testing.T) { 14 | rawAccount := &shadowsocks.Account{ 15 | CipherType: shadowsocks.CipherType_AES_128_GCM, 16 | Password: "test", 17 | } 18 | account, err := rawAccount.AsAccount() 19 | common.Must(err) 20 | 21 | cipher := account.(*shadowsocks.MemoryAccount).Cipher 22 | 23 | key := make([]byte, cipher.KeySize()) 24 | common.Must2(rand.Read(key)) 25 | 26 | payload := make([]byte, 1024) 27 | common.Must2(rand.Read(payload)) 28 | 29 | b1 := buf.New() 30 | common.Must2(b1.ReadFullFrom(rand.Reader, cipher.IVSize())) 31 | common.Must2(b1.Write(payload)) 32 | common.Must(cipher.EncodePacket(key, b1)) 33 | 34 | common.Must(cipher.DecodePacket(key, b1)) 35 | if diff := cmp.Diff(b1.Bytes(), payload); diff != "" { 36 | t.Error(diff) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testing/scenarios/common_coverage.go: -------------------------------------------------------------------------------- 1 | //go:build coverage 2 | // +build coverage 3 | 4 | package scenarios 5 | 6 | import ( 7 | "bytes" 8 | "os" 9 | "os/exec" 10 | 11 | "github.com/xtls/xray-core/common/uuid" 12 | ) 13 | 14 | func BuildXray() error { 15 | genTestBinaryPath() 16 | if _, err := os.Stat(testBinaryPath); err == nil { 17 | return nil 18 | } 19 | 20 | cmd := exec.Command("go", "test", "-tags", "coverage coveragemain", "-coverpkg", "github.com/xtls/xray-core/...", "-c", "-o", testBinaryPath, GetSourcePath()) 21 | return cmd.Run() 22 | } 23 | 24 | func RunXrayProtobuf(config []byte) *exec.Cmd { 25 | genTestBinaryPath() 26 | 27 | covDir := os.Getenv("XRAY_COV") 28 | os.MkdirAll(covDir, os.ModeDir) 29 | randomID := uuid.New() 30 | profile := randomID.String() + ".out" 31 | proc := exec.Command(testBinaryPath, "-config=stdin:", "-format=pb", "-test.run", "TestRunMainForCoverage", "-test.coverprofile", profile, "-test.outputdir", covDir) 32 | proc.Stdin = bytes.NewBuffer(config) 33 | proc.Stderr = os.Stderr 34 | proc.Stdout = os.Stdout 35 | 36 | return proc 37 | } 38 | -------------------------------------------------------------------------------- /transport/internet/header.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/errors" 9 | ) 10 | 11 | type PacketHeader interface { 12 | Size() int32 13 | Serialize([]byte) 14 | } 15 | 16 | func CreatePacketHeader(config interface{}) (PacketHeader, error) { 17 | header, err := common.CreateObject(context.Background(), config) 18 | if err != nil { 19 | return nil, err 20 | } 21 | if h, ok := header.(PacketHeader); ok { 22 | return h, nil 23 | } 24 | return nil, errors.New("not a packet header") 25 | } 26 | 27 | type ConnectionAuthenticator interface { 28 | Client(net.Conn) net.Conn 29 | Server(net.Conn) net.Conn 30 | } 31 | 32 | func CreateConnectionAuthenticator(config interface{}) (ConnectionAuthenticator, error) { 33 | auth, err := common.CreateObject(context.Background(), config) 34 | if err != nil { 35 | return nil, err 36 | } 37 | if a, ok := auth.(ConnectionAuthenticator); ok { 38 | return a, nil 39 | } 40 | return nil, errors.New("not a ConnectionAuthenticator") 41 | } 42 | -------------------------------------------------------------------------------- /infra/conf/freedom_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | "github.com/xtls/xray-core/common/protocol" 8 | . "github.com/xtls/xray-core/infra/conf" 9 | "github.com/xtls/xray-core/proxy/freedom" 10 | "github.com/xtls/xray-core/transport/internet" 11 | ) 12 | 13 | func TestFreedomConfig(t *testing.T) { 14 | creator := func() Buildable { 15 | return new(FreedomConfig) 16 | } 17 | 18 | runMultiTestCase(t, []TestCase{ 19 | { 20 | Input: `{ 21 | "domainStrategy": "AsIs", 22 | "redirect": "127.0.0.1:3366", 23 | "userLevel": 1 24 | }`, 25 | Parser: loadJSON(creator), 26 | Output: &freedom.Config{ 27 | DomainStrategy: internet.DomainStrategy_AS_IS, 28 | DestinationOverride: &freedom.DestinationOverride{ 29 | Server: &protocol.ServerEndpoint{ 30 | Address: &net.IPOrDomain{ 31 | Address: &net.IPOrDomain_Ip{ 32 | Ip: []byte{127, 0, 0, 1}, 33 | }, 34 | }, 35 | Port: 3366, 36 | }, 37 | }, 38 | UserLevel: 1, 39 | }, 40 | }, 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /transport/internet/udp/hub_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package udp 5 | 6 | import ( 7 | "syscall" 8 | 9 | "github.com/xtls/xray-core/common/net" 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | func RetrieveOriginalDest(oob []byte) net.Destination { 14 | msgs, err := syscall.ParseSocketControlMessage(oob) 15 | if err != nil { 16 | return net.Destination{} 17 | } 18 | for _, msg := range msgs { 19 | if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR { 20 | ip := net.IPAddress(msg.Data[4:8]) 21 | port := net.PortFromBytes(msg.Data[2:4]) 22 | return net.UDPDestination(ip, port) 23 | } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == unix.IPV6_RECVORIGDSTADDR { 24 | ip := net.IPAddress(msg.Data[8:24]) 25 | port := net.PortFromBytes(msg.Data[2:4]) 26 | return net.UDPDestination(ip, port) 27 | } 28 | } 29 | return net.Destination{} 30 | } 31 | 32 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) { 33 | return conn.ReadMsgUDP(payload, oob) 34 | } 35 | -------------------------------------------------------------------------------- /common/mux/session_test.go: -------------------------------------------------------------------------------- 1 | package mux_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/xtls/xray-core/common/mux" 7 | ) 8 | 9 | func TestSessionManagerAdd(t *testing.T) { 10 | m := NewSessionManager() 11 | 12 | s := m.Allocate(&ClientStrategy{}) 13 | if s.ID != 1 { 14 | t.Error("id: ", s.ID) 15 | } 16 | if m.Size() != 1 { 17 | t.Error("size: ", m.Size()) 18 | } 19 | 20 | s = m.Allocate(&ClientStrategy{}) 21 | if s.ID != 2 { 22 | t.Error("id: ", s.ID) 23 | } 24 | if m.Size() != 2 { 25 | t.Error("size: ", m.Size()) 26 | } 27 | 28 | s = &Session{ 29 | ID: 4, 30 | } 31 | m.Add(s) 32 | if s.ID != 4 { 33 | t.Error("id: ", s.ID) 34 | } 35 | if m.Size() != 3 { 36 | t.Error("size: ", m.Size()) 37 | } 38 | } 39 | 40 | func TestSessionManagerClose(t *testing.T) { 41 | m := NewSessionManager() 42 | s := m.Allocate(&ClientStrategy{}) 43 | 44 | if m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) { 45 | t.Error("able to close") 46 | } 47 | m.Remove(false, s.ID) 48 | if !m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) { 49 | t.Error("not able to close") 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /transport/internet/filelocker_other.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package internet 5 | 6 | import ( 7 | "context" 8 | "os" 9 | 10 | "github.com/xtls/xray-core/common/errors" 11 | "golang.org/x/sys/unix" 12 | ) 13 | 14 | // Acquire lock 15 | func (fl *FileLocker) Acquire() error { 16 | f, err := os.Create(fl.path) 17 | if err != nil { 18 | return err 19 | } 20 | if err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil { 21 | f.Close() 22 | return errors.New("failed to lock file: ", fl.path).Base(err) 23 | } 24 | fl.file = f 25 | return nil 26 | } 27 | 28 | // Release lock 29 | func (fl *FileLocker) Release() { 30 | if err := unix.Flock(int(fl.file.Fd()), unix.LOCK_UN); err != nil { 31 | errors.LogInfoInner(context.Background(), err, "failed to unlock file: ", fl.path) 32 | } 33 | if err := fl.file.Close(); err != nil { 34 | errors.LogInfoInner(context.Background(), err, "failed to close file: ", fl.path) 35 | } 36 | if err := os.Remove(fl.path); err != nil { 37 | errors.LogInfoInner(context.Background(), err, "failed to remove file: ", fl.path) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # macOS specific files 15 | .DS_Store 16 | 17 | # IDE/editor specific files 18 | .idea/ 19 | .vscode/ 20 | *.swp 21 | *.swo 22 | 23 | # Archives and compressed files 24 | *.zip 25 | *.tar.gz 26 | *.tar 27 | *.gz 28 | *.bz2 29 | 30 | # Go build binaries 31 | xray 32 | xray_softfloat 33 | mockgen 34 | vprotogen 35 | !infra/vprotogen/ 36 | errorgen 37 | !common/errors/errorgen/ 38 | *.dat 39 | 40 | # Build assets 41 | /build_assets/ 42 | 43 | # Output from dlv test 44 | **/debug.* 45 | 46 | # Certificates and keys 47 | *.crt 48 | *.key 49 | 50 | # Dependency directories (uncomment if needed) 51 | # vendor/ 52 | 53 | # Logs 54 | *.log 55 | 56 | # Coverage reports 57 | coverage.* 58 | 59 | # Node modules (in case of frontend assets) 60 | node_modules/ 61 | 62 | # System files 63 | Thumbs.db 64 | ehthumbs.db 65 | 66 | # Other common ignores 67 | *.bak 68 | *.tmp 69 | -------------------------------------------------------------------------------- /infra/conf/dns_proxy.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/errors" 5 | "github.com/xtls/xray-core/common/net" 6 | "github.com/xtls/xray-core/proxy/dns" 7 | "google.golang.org/protobuf/proto" 8 | ) 9 | 10 | type DNSOutboundConfig struct { 11 | Network Network `json:"network"` 12 | Address *Address `json:"address"` 13 | Port uint16 `json:"port"` 14 | UserLevel uint32 `json:"userLevel"` 15 | NonIPQuery string `json:"nonIPQuery"` 16 | BlockTypes []int32 `json:"blockTypes"` 17 | } 18 | 19 | func (c *DNSOutboundConfig) Build() (proto.Message, error) { 20 | config := &dns.Config{ 21 | Server: &net.Endpoint{ 22 | Network: c.Network.Build(), 23 | Port: uint32(c.Port), 24 | }, 25 | UserLevel: c.UserLevel, 26 | } 27 | if c.Address != nil { 28 | config.Server.Address = c.Address.Build() 29 | } 30 | switch c.NonIPQuery { 31 | case "", "reject", "drop", "skip": 32 | default: 33 | return nil, errors.New(`unknown "nonIPQuery": `, c.NonIPQuery) 34 | } 35 | config.Non_IPQuery = c.NonIPQuery 36 | config.BlockTypes = c.BlockTypes 37 | return config, nil 38 | } 39 | -------------------------------------------------------------------------------- /common/protocol/id.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "crypto/md5" 5 | 6 | "github.com/xtls/xray-core/common" 7 | "github.com/xtls/xray-core/common/uuid" 8 | ) 9 | 10 | const ( 11 | IDBytesLen = 16 12 | ) 13 | 14 | // The ID of en entity, in the form of a UUID. 15 | type ID struct { 16 | uuid uuid.UUID 17 | cmdKey [IDBytesLen]byte 18 | } 19 | 20 | // Equals returns true if this ID equals to the other one. 21 | func (id *ID) Equals(another *ID) bool { 22 | return id.uuid.Equals(&(another.uuid)) 23 | } 24 | 25 | func (id *ID) Bytes() []byte { 26 | return id.uuid.Bytes() 27 | } 28 | 29 | func (id *ID) String() string { 30 | return id.uuid.String() 31 | } 32 | 33 | func (id *ID) UUID() uuid.UUID { 34 | return id.uuid 35 | } 36 | 37 | func (id ID) CmdKey() []byte { 38 | return id.cmdKey[:] 39 | } 40 | 41 | // NewID returns an ID with given UUID. 42 | func NewID(uuid uuid.UUID) *ID { 43 | id := &ID{uuid: uuid} 44 | md5hash := md5.New() 45 | common.Must2(md5hash.Write(uuid.Bytes())) 46 | common.Must2(md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))) 47 | md5hash.Sum(id.cmdKey[:0]) 48 | return id 49 | } 50 | -------------------------------------------------------------------------------- /app/observatory/burst/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.core.app.observatory.burst; 4 | option csharp_namespace = "Xray.App.Observatory.Burst"; 5 | option go_package = "github.com/xtls/xray-core/app/observatory/burst"; 6 | option java_package = "com.xray.app.observatory.burst"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | /* @Document The selectors for outbound under observation 11 | */ 12 | repeated string subject_selector = 2; 13 | 14 | HealthPingConfig ping_config = 3; 15 | } 16 | 17 | message HealthPingConfig { 18 | // destination url, need 204 for success return 19 | // default https://connectivitycheck.gstatic.com/generate_204 20 | string destination = 1; 21 | // connectivity check url 22 | string connectivity = 2; 23 | // health check interval, int64 values of time.Duration 24 | int64 interval = 3; 25 | // sampling count is the amount of recent ping results which are kept for calculation 26 | int32 samplingCount = 4; 27 | // ping timeout, int64 values of time.Duration 28 | int64 timeout = 5; 29 | // http method to make request 30 | string httpMethod = 6; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /main/commands/all/tls/certchainhash.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/xtls/xray-core/main/commands/base" 9 | "github.com/xtls/xray-core/transport/internet/tls" 10 | ) 11 | 12 | var cmdCertChainHash = &base.Command{ 13 | UsageLine: "{{.Exec}} certChainHash", 14 | Short: "Calculate TLS certificates hash.", 15 | Long: ` 16 | xray tls certChainHash --cert 17 | Calculate TLS certificate chain hash. 18 | `, 19 | } 20 | 21 | func init() { 22 | cmdCertChainHash.Run = executeCertChainHash // break init loop 23 | } 24 | 25 | var input = cmdCertChainHash.Flag.String("cert", "fullchain.pem", "The file path of the certificates chain") 26 | 27 | func executeCertChainHash(cmd *base.Command, args []string) { 28 | fs := flag.NewFlagSet("certChainHash", flag.ContinueOnError) 29 | if err := fs.Parse(args); err != nil { 30 | fmt.Println(err) 31 | return 32 | } 33 | certContent, err := os.ReadFile(*input) 34 | if err != nil { 35 | fmt.Println(err) 36 | return 37 | } 38 | certChainHashB64 := tls.CalculatePEMCertChainSHA256Hash(certContent) 39 | fmt.Println(certChainHashB64) 40 | } 41 | -------------------------------------------------------------------------------- /transport/internet/tls/pin.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import ( 4 | "crypto/sha256" 5 | "crypto/x509" 6 | "encoding/base64" 7 | "encoding/pem" 8 | ) 9 | 10 | func CalculatePEMCertChainSHA256Hash(certContent []byte) string { 11 | var certChain [][]byte 12 | for { 13 | block, remain := pem.Decode(certContent) 14 | if block == nil { 15 | break 16 | } 17 | certChain = append(certChain, block.Bytes) 18 | certContent = remain 19 | } 20 | certChainHash := GenerateCertChainHash(certChain) 21 | certChainHashB64 := base64.StdEncoding.EncodeToString(certChainHash) 22 | return certChainHashB64 23 | } 24 | 25 | func GenerateCertChainHash(rawCerts [][]byte) []byte { 26 | var hashValue []byte 27 | for _, certValue := range rawCerts { 28 | out := sha256.Sum256(certValue) 29 | if hashValue == nil { 30 | hashValue = out[:] 31 | } else { 32 | newHashValue := sha256.Sum256(append(hashValue, out[:]...)) 33 | hashValue = newHashValue[:] 34 | } 35 | } 36 | return hashValue 37 | } 38 | 39 | func GenerateCertPublicKeyHash(cert *x509.Certificate) []byte { 40 | out := sha256.Sum256(cert.RawSubjectPublicKeyInfo) 41 | return out[:] 42 | } 43 | -------------------------------------------------------------------------------- /transport/pipe/reader.go: -------------------------------------------------------------------------------- 1 | package pipe 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/xtls/xray-core/common/buf" 7 | ) 8 | 9 | // Reader is a buf.Reader that reads content from a pipe. 10 | type Reader struct { 11 | pipe *pipe 12 | } 13 | 14 | // ReadMultiBuffer implements buf.Reader. 15 | func (r *Reader) ReadMultiBuffer() (buf.MultiBuffer, error) { 16 | return r.pipe.ReadMultiBuffer() 17 | } 18 | 19 | // ReadMultiBufferTimeout reads content from a pipe within the given duration, or returns buf.ErrTimeout otherwise. 20 | func (r *Reader) ReadMultiBufferTimeout(d time.Duration) (buf.MultiBuffer, error) { 21 | return r.pipe.ReadMultiBufferTimeout(d) 22 | } 23 | 24 | // Interrupt implements common.Interruptible. 25 | func (r *Reader) Interrupt() { 26 | r.pipe.Interrupt() 27 | } 28 | 29 | // ReturnAnError makes ReadMultiBuffer return an error, only once. 30 | func (r *Reader) ReturnAnError(err error) { 31 | r.pipe.errChan <- err 32 | } 33 | 34 | // Recover catches an error set by ReturnAnError, if exists. 35 | func (r *Reader) Recover() (err error) { 36 | select { 37 | case err = <-r.pipe.errChan: 38 | default: 39 | } 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /features/routing/dispatcher.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/xtls/xray-core/common/net" 7 | "github.com/xtls/xray-core/features" 8 | "github.com/xtls/xray-core/transport" 9 | ) 10 | 11 | // Dispatcher is a feature that dispatches inbound requests to outbound handlers based on rules. 12 | // Dispatcher is required to be registered in a Xray instance to make Xray function properly. 13 | // 14 | // xray:api:stable 15 | type Dispatcher interface { 16 | features.Feature 17 | 18 | // Dispatch returns a Ray for transporting data for the given request. 19 | Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) 20 | DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error 21 | } 22 | 23 | // DispatcherType returns the type of Dispatcher interface. Can be used to implement common.HasType. 24 | // 25 | // xray:api:stable 26 | func DispatcherType() interface{} { 27 | return (*Dispatcher)(nil) 28 | } 29 | 30 | // Just for type assertion 31 | type WrapLinkDispatcher interface { 32 | Dispatcher 33 | WrapLink(ctx context.Context, link *transport.Link) *transport.Link 34 | } 35 | -------------------------------------------------------------------------------- /common/protocol/tls/cert/privateKey.go: -------------------------------------------------------------------------------- 1 | package cert 2 | 3 | import ( 4 | "crypto/x509/pkix" 5 | "encoding/asn1" 6 | "math/big" 7 | ) 8 | 9 | type ecPrivateKey struct { 10 | Version int 11 | PrivateKey []byte 12 | NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` 13 | PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` 14 | } 15 | 16 | type pkcs8 struct { 17 | Version int 18 | Algo pkix.AlgorithmIdentifier 19 | PrivateKey []byte 20 | // Optional attributes omitted. 21 | } 22 | 23 | type pkcs1AdditionalRSAPrime struct { 24 | Prime *big.Int 25 | 26 | // We ignore these values because rsa will calculate them. 27 | Exp *big.Int 28 | Coeff *big.Int 29 | } 30 | 31 | type pkcs1PrivateKey struct { 32 | Version int 33 | N *big.Int 34 | E int 35 | D *big.Int 36 | P *big.Int 37 | Q *big.Int 38 | // We ignore these values, if present, because rsa will calculate them. 39 | Dp *big.Int `asn1:"optional"` 40 | Dq *big.Int `asn1:"optional"` 41 | Qinv *big.Int `asn1:"optional"` 42 | 43 | AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"` 44 | } 45 | -------------------------------------------------------------------------------- /common/strmatcher/full_matcher_test.go: -------------------------------------------------------------------------------- 1 | package strmatcher_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | . "github.com/xtls/xray-core/common/strmatcher" 8 | ) 9 | 10 | func TestFullMatcherGroup(t *testing.T) { 11 | g := new(FullMatcherGroup) 12 | g.Add("example.com", 1) 13 | g.Add("google.com", 2) 14 | g.Add("x.a.com", 3) 15 | g.Add("x.y.com", 4) 16 | g.Add("x.y.com", 6) 17 | 18 | testCases := []struct { 19 | Domain string 20 | Result []uint32 21 | }{ 22 | { 23 | Domain: "example.com", 24 | Result: []uint32{1}, 25 | }, 26 | { 27 | Domain: "y.com", 28 | Result: nil, 29 | }, 30 | { 31 | Domain: "x.y.com", 32 | Result: []uint32{4, 6}, 33 | }, 34 | } 35 | 36 | for _, testCase := range testCases { 37 | r := g.Match(testCase.Domain) 38 | if !reflect.DeepEqual(r, testCase.Result) { 39 | t.Error("Failed to match domain: ", testCase.Domain, ", expect ", testCase.Result, ", but got ", r) 40 | } 41 | } 42 | } 43 | 44 | func TestEmptyFullMatcherGroup(t *testing.T) { 45 | g := new(FullMatcherGroup) 46 | r := g.Match("example.com") 47 | if len(r) != 0 { 48 | t.Error("Expect [], but ", r) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /common/platform/others.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package platform 5 | 6 | import ( 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | func LineSeparator() string { 12 | return "\n" 13 | } 14 | 15 | // GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations 16 | func GetAssetLocation(file string) string { 17 | assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir) 18 | defPath := filepath.Join(assetPath, file) 19 | for _, p := range []string{ 20 | defPath, 21 | filepath.Join("/usr/local/share/xray/", file), 22 | filepath.Join("/usr/share/xray/", file), 23 | filepath.Join("/opt/share/xray/", file), 24 | } { 25 | if _, err := os.Stat(p); os.IsNotExist(err) { 26 | continue 27 | } 28 | 29 | // asset found 30 | return p 31 | } 32 | 33 | // asset not found, let the caller throw out the error 34 | return defPath 35 | } 36 | 37 | // GetCertLocation searches for `file` in the env dir and the executable dir 38 | func GetCertLocation(file string) string { 39 | certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir) 40 | return filepath.Join(certPath, file) 41 | } 42 | -------------------------------------------------------------------------------- /common/strmatcher/matchers.go: -------------------------------------------------------------------------------- 1 | package strmatcher 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | type fullMatcher string 9 | 10 | func (m fullMatcher) Match(s string) bool { 11 | return string(m) == s 12 | } 13 | 14 | func (m fullMatcher) String() string { 15 | return "full:" + string(m) 16 | } 17 | 18 | type substrMatcher string 19 | 20 | func (m substrMatcher) Match(s string) bool { 21 | return strings.Contains(s, string(m)) 22 | } 23 | 24 | func (m substrMatcher) String() string { 25 | return "keyword:" + string(m) 26 | } 27 | 28 | type domainMatcher string 29 | 30 | func (m domainMatcher) Match(s string) bool { 31 | pattern := string(m) 32 | if !strings.HasSuffix(s, pattern) { 33 | return false 34 | } 35 | return len(s) == len(pattern) || s[len(s)-len(pattern)-1] == '.' 36 | } 37 | 38 | func (m domainMatcher) String() string { 39 | return "domain:" + string(m) 40 | } 41 | 42 | type regexMatcher struct { 43 | pattern *regexp.Regexp 44 | } 45 | 46 | func (m *regexMatcher) Match(s string) bool { 47 | return m.pattern.MatchString(s) 48 | } 49 | 50 | func (m *regexMatcher) String() string { 51 | return "regexp:" + m.pattern.String() 52 | } 53 | -------------------------------------------------------------------------------- /transport/internet/sockopt_linux_test.go: -------------------------------------------------------------------------------- 1 | package internet_test 2 | 3 | import ( 4 | "context" 5 | "syscall" 6 | "testing" 7 | 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/common/net" 10 | "github.com/xtls/xray-core/testing/servers/tcp" 11 | . "github.com/xtls/xray-core/transport/internet" 12 | ) 13 | 14 | func TestSockOptMark(t *testing.T) { 15 | t.Skip("requires CAP_NET_ADMIN") 16 | 17 | tcpServer := tcp.Server{ 18 | MsgProcessor: func(b []byte) []byte { 19 | return b 20 | }, 21 | } 22 | dest, err := tcpServer.Start() 23 | common.Must(err) 24 | defer tcpServer.Close() 25 | 26 | const mark = 1 27 | dialer := DefaultSystemDialer{} 28 | conn, err := dialer.Dial(context.Background(), nil, dest, &SocketConfig{Mark: mark}) 29 | common.Must(err) 30 | defer conn.Close() 31 | 32 | rawConn, err := conn.(*net.TCPConn).SyscallConn() 33 | common.Must(err) 34 | err = rawConn.Control(func(fd uintptr) { 35 | m, err := syscall.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK) 36 | common.Must(err) 37 | if mark != m { 38 | t.Fatal("unexpected connection mark", m, " want ", mark) 39 | } 40 | }) 41 | common.Must(err) 42 | } 43 | -------------------------------------------------------------------------------- /app/router/balancing_override.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | sync "sync" 5 | 6 | "github.com/xtls/xray-core/common/errors" 7 | ) 8 | 9 | func (r *Router) OverrideBalancer(balancer string, target string) error { 10 | var b *Balancer 11 | for tag, bl := range r.balancers { 12 | if tag == balancer { 13 | b = bl 14 | break 15 | } 16 | } 17 | if b == nil { 18 | return errors.New("balancer '", balancer, "' not found") 19 | } 20 | b.override.Put(target) 21 | return nil 22 | } 23 | 24 | type overrideSettings struct { 25 | target string 26 | } 27 | 28 | type override struct { 29 | access sync.RWMutex 30 | settings overrideSettings 31 | } 32 | 33 | // Get gets the override settings 34 | func (o *override) Get() string { 35 | o.access.RLock() 36 | defer o.access.RUnlock() 37 | return o.settings.target 38 | } 39 | 40 | // Put updates the override settings 41 | func (o *override) Put(target string) { 42 | o.access.Lock() 43 | defer o.access.Unlock() 44 | o.settings.target = target 45 | } 46 | 47 | // Clear clears the override settings 48 | func (o *override) Clear() { 49 | o.access.Lock() 50 | defer o.access.Unlock() 51 | o.settings.target = "" 52 | } 53 | -------------------------------------------------------------------------------- /main/commands/all/api/outbounds_list.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | handlerService "github.com/xtls/xray-core/app/proxyman/command" 5 | "github.com/xtls/xray-core/main/commands/base" 6 | ) 7 | 8 | var cmdListOutbounds = &base.Command{ 9 | CustomFlags: true, 10 | UsageLine: "{{.Exec}} api lso [--server=127.0.0.1:8080]", 11 | Short: "List outbounds", 12 | Long: ` 13 | List outbounds in Xray. 14 | 15 | Arguments: 16 | 17 | -s, -server 18 | The API server address. Default 127.0.0.1:8080 19 | 20 | -t, -timeout 21 | Timeout in seconds for calling API. Default 3 22 | 23 | Example: 24 | 25 | {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 26 | `, 27 | Run: executeListOutbounds, 28 | } 29 | 30 | func executeListOutbounds(cmd *base.Command, args []string) { 31 | setSharedFlags(cmd) 32 | cmd.Flag.Parse(args) 33 | 34 | conn, ctx, close := dialAPIServer() 35 | defer close() 36 | 37 | client := handlerService.NewHandlerServiceClient(conn) 38 | resp, err := client.ListOutbounds(ctx, &handlerService.ListOutboundsRequest{}) 39 | if err != nil { 40 | base.Fatalf("failed to list outbounds: %s", err) 41 | } 42 | showJSONResponse(resp) 43 | } 44 | -------------------------------------------------------------------------------- /infra/conf/dokodemo.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common/errors" 5 | "github.com/xtls/xray-core/common/net" 6 | "github.com/xtls/xray-core/proxy/dokodemo" 7 | "google.golang.org/protobuf/proto" 8 | ) 9 | 10 | type DokodemoConfig struct { 11 | Address *Address `json:"address"` 12 | Port uint16 `json:"port"` 13 | PortMap map[string]string `json:"portMap"` 14 | Network *NetworkList `json:"network"` 15 | FollowRedirect bool `json:"followRedirect"` 16 | UserLevel uint32 `json:"userLevel"` 17 | } 18 | 19 | func (v *DokodemoConfig) Build() (proto.Message, error) { 20 | config := new(dokodemo.Config) 21 | if v.Address != nil { 22 | config.Address = v.Address.Build() 23 | } 24 | config.Port = uint32(v.Port) 25 | config.PortMap = v.PortMap 26 | for _, v := range config.PortMap { 27 | if _, _, err := net.SplitHostPort(v); err != nil { 28 | return nil, errors.New("invalid portMap: ", v).Base(err) 29 | } 30 | } 31 | config.Networks = v.Network.Build() 32 | config.FollowRedirect = v.FollowRedirect 33 | config.UserLevel = v.UserLevel 34 | return config, nil 35 | } 36 | -------------------------------------------------------------------------------- /main/commands/all/api/stats_sys.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | statsService "github.com/xtls/xray-core/app/stats/command" 5 | "github.com/xtls/xray-core/main/commands/base" 6 | ) 7 | 8 | var cmdSysStats = &base.Command{ 9 | CustomFlags: true, 10 | UsageLine: "{{.Exec}} api statssys [--server=127.0.0.1:8080]", 11 | Short: "Retrieve system statistics", 12 | Long: ` 13 | Retrieve system statistics from Xray. 14 | 15 | Arguments: 16 | 17 | -s, -server 18 | The API server address. Default 127.0.0.1:8080 19 | 20 | -t, -timeout 21 | Timeout in seconds for calling API. Default 3 22 | 23 | Example: 24 | 25 | {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 26 | `, 27 | Run: executeSysStats, 28 | } 29 | 30 | func executeSysStats(cmd *base.Command, args []string) { 31 | setSharedFlags(cmd) 32 | cmd.Flag.Parse(args) 33 | 34 | conn, ctx, close := dialAPIServer() 35 | defer close() 36 | 37 | client := statsService.NewStatsServiceClient(conn) 38 | r := &statsService.SysStatsRequest{} 39 | resp, err := client.GetSysStats(ctx, r) 40 | if err != nil { 41 | base.Fatalf("failed to get sys stats: %s", err) 42 | } 43 | showJSONResponse(resp) 44 | } 45 | -------------------------------------------------------------------------------- /transport/internet/kcp/output.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "io" 5 | "sync" 6 | 7 | "github.com/xtls/xray-core/common/buf" 8 | "github.com/xtls/xray-core/common/retry" 9 | ) 10 | 11 | type SegmentWriter interface { 12 | Write(seg Segment) error 13 | } 14 | 15 | type SimpleSegmentWriter struct { 16 | sync.Mutex 17 | buffer *buf.Buffer 18 | writer io.Writer 19 | } 20 | 21 | func NewSegmentWriter(writer io.Writer) SegmentWriter { 22 | return &SimpleSegmentWriter{ 23 | writer: writer, 24 | buffer: buf.New(), 25 | } 26 | } 27 | 28 | func (w *SimpleSegmentWriter) Write(seg Segment) error { 29 | w.Lock() 30 | defer w.Unlock() 31 | 32 | w.buffer.Clear() 33 | rawBytes := w.buffer.Extend(seg.ByteSize()) 34 | seg.Serialize(rawBytes) 35 | _, err := w.writer.Write(w.buffer.Bytes()) 36 | return err 37 | } 38 | 39 | type RetryableWriter struct { 40 | writer SegmentWriter 41 | } 42 | 43 | func NewRetryableWriter(writer SegmentWriter) SegmentWriter { 44 | return &RetryableWriter{ 45 | writer: writer, 46 | } 47 | } 48 | 49 | func (w *RetryableWriter) Write(seg Segment) error { 50 | return retry.Timed(5, 100).On(func() error { 51 | return w.writer.Write(seg) 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /main/commands/all/api/logger_restart.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | logService "github.com/xtls/xray-core/app/log/command" 5 | "github.com/xtls/xray-core/main/commands/base" 6 | ) 7 | 8 | var cmdRestartLogger = &base.Command{ 9 | CustomFlags: true, 10 | UsageLine: "{{.Exec}} api restartlogger [--server=127.0.0.1:8080]", 11 | Short: "Restart the logger", 12 | Long: ` 13 | Restart the logger of Xray. 14 | 15 | Arguments: 16 | 17 | -s, -server 18 | The API server address. Default 127.0.0.1:8080 19 | 20 | -t, -timeout 21 | Timeout in seconds for calling API. Default 3 22 | 23 | Example: 24 | 25 | {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 26 | `, 27 | Run: executeRestartLogger, 28 | } 29 | 30 | func executeRestartLogger(cmd *base.Command, args []string) { 31 | setSharedFlags(cmd) 32 | cmd.Flag.Parse(args) 33 | 34 | conn, ctx, close := dialAPIServer() 35 | defer close() 36 | 37 | client := logService.NewLoggerServiceClient(conn) 38 | r := &logService.RestartLoggerRequest{} 39 | resp, err := client.RestartLogger(ctx, r) 40 | if err != nil { 41 | base.Fatalf("failed to restart logger: %s", err) 42 | } 43 | showJSONResponse(resp) 44 | } 45 | -------------------------------------------------------------------------------- /proxy/blackhole/blackhole_test.go: -------------------------------------------------------------------------------- 1 | package blackhole_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/xtls/xray-core/common" 8 | "github.com/xtls/xray-core/common/buf" 9 | "github.com/xtls/xray-core/common/serial" 10 | "github.com/xtls/xray-core/common/session" 11 | "github.com/xtls/xray-core/proxy/blackhole" 12 | "github.com/xtls/xray-core/transport" 13 | "github.com/xtls/xray-core/transport/pipe" 14 | ) 15 | 16 | func TestBlackholeHTTPResponse(t *testing.T) { 17 | ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{}}) 18 | handler, err := blackhole.New(ctx, &blackhole.Config{ 19 | Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}), 20 | }) 21 | common.Must(err) 22 | 23 | reader, writer := pipe.New(pipe.WithoutSizeLimit()) 24 | 25 | var mb buf.MultiBuffer 26 | var rerr error 27 | go func() { 28 | b, e := reader.ReadMultiBuffer() 29 | mb = b 30 | rerr = e 31 | }() 32 | 33 | link := transport.Link{ 34 | Reader: reader, 35 | Writer: writer, 36 | } 37 | common.Must(handler.Process(ctx, &link, nil)) 38 | common.Must(rerr) 39 | if mb.IsEmpty() { 40 | t.Error("expect http response, but nothing") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/policy/manager_test.go: -------------------------------------------------------------------------------- 1 | package policy_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | . "github.com/xtls/xray-core/app/policy" 9 | "github.com/xtls/xray-core/common" 10 | "github.com/xtls/xray-core/features/policy" 11 | ) 12 | 13 | func TestPolicy(t *testing.T) { 14 | manager, err := New(context.Background(), &Config{ 15 | Level: map[uint32]*Policy{ 16 | 0: { 17 | Timeout: &Policy_Timeout{ 18 | Handshake: &Second{ 19 | Value: 2, 20 | }, 21 | }, 22 | }, 23 | }, 24 | }) 25 | common.Must(err) 26 | 27 | pDefault := policy.SessionDefault() 28 | 29 | { 30 | p := manager.ForLevel(0) 31 | if p.Timeouts.Handshake != 2*time.Second { 32 | t.Error("expect 2 sec timeout, but got ", p.Timeouts.Handshake) 33 | } 34 | if p.Timeouts.ConnectionIdle != pDefault.Timeouts.ConnectionIdle { 35 | t.Error("expect ", pDefault.Timeouts.ConnectionIdle, " sec timeout, but got ", p.Timeouts.ConnectionIdle) 36 | } 37 | } 38 | 39 | { 40 | p := manager.ForLevel(1) 41 | if p.Timeouts.Handshake != pDefault.Timeouts.Handshake { 42 | t.Error("expect ", pDefault.Timeouts.Handshake, " sec timeout, but got ", p.Timeouts.Handshake) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/mocks.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | //go:generate go run github.com/golang/mock/mockgen -package mocks -destination ../testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer 4 | //go:generate go run github.com/golang/mock/mockgen -package mocks -destination ../testing/mocks/log.go -mock_names Handler=LogHandler github.com/xtls/xray-core/common/log Handler 5 | //go:generate go run github.com/golang/mock/mockgen -package mocks -destination ../testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory github.com/xtls/xray-core/common/mux ClientWorkerFactory 6 | //go:generate go run github.com/golang/mock/mockgen -package mocks -destination ../testing/mocks/dns.go -mock_names Client=DNSClient github.com/xtls/xray-core/features/dns Client 7 | //go:generate go run github.com/golang/mock/mockgen -package mocks -destination ../testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector github.com/xtls/xray-core/features/outbound Manager,HandlerSelector 8 | //go:generate go run github.com/golang/mock/mockgen -package mocks -destination ../testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound github.com/xtls/xray-core/proxy Inbound,Outbound 9 | -------------------------------------------------------------------------------- /transport/internet/reality/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.reality; 4 | option csharp_namespace = "Xray.Transport.Internet.Reality"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/reality"; 6 | option java_package = "com.xray.transport.internet.reality"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | bool show = 1; 11 | string dest = 2; 12 | string type = 3; 13 | uint64 xver = 4; 14 | repeated string server_names = 5; 15 | bytes private_key = 6; 16 | bytes min_client_ver = 7; 17 | bytes max_client_ver = 8; 18 | uint64 max_time_diff = 9; 19 | repeated bytes short_ids = 10; 20 | 21 | bytes mldsa65_seed = 11; 22 | LimitFallback limit_fallback_upload = 12; 23 | LimitFallback limit_fallback_download = 13; 24 | 25 | string Fingerprint = 21; 26 | string server_name = 22; 27 | bytes public_key = 23; 28 | bytes short_id = 24; 29 | bytes mldsa65_verify = 25; 30 | string spider_x = 26; 31 | repeated int64 spider_y = 27; 32 | 33 | string master_key_log = 31; 34 | } 35 | 36 | message LimitFallback { 37 | uint64 after_bytes = 1; 38 | uint64 bytes_per_sec = 2; 39 | uint64 burst_bytes_per_sec = 3; 40 | } 41 | -------------------------------------------------------------------------------- /proxy/socks/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.socks; 4 | option csharp_namespace = "Xray.Proxy.Socks"; 5 | option go_package = "github.com/xtls/xray-core/proxy/socks"; 6 | option java_package = "com.xray.proxy.socks"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/address.proto"; 10 | import "common/protocol/server_spec.proto"; 11 | 12 | // Account represents a Socks account. 13 | message Account { 14 | string username = 1; 15 | string password = 2; 16 | } 17 | 18 | // AuthType is the authentication type of Socks proxy. 19 | enum AuthType { 20 | // NO_AUTH is for anonymous authentication. 21 | NO_AUTH = 0; 22 | // PASSWORD is for username/password authentication. 23 | PASSWORD = 1; 24 | } 25 | 26 | // ServerConfig is the protobuf config for Socks server. 27 | message ServerConfig { 28 | AuthType auth_type = 1; 29 | map accounts = 2; 30 | xray.common.net.IPOrDomain address = 3; 31 | bool udp_enabled = 4; 32 | uint32 user_level = 6; 33 | } 34 | 35 | // ClientConfig is the protobuf config for Socks client. 36 | message ClientConfig { 37 | // Sever is a list of Socks server addresses. 38 | xray.common.protocol.ServerEndpoint server = 1; 39 | } 40 | -------------------------------------------------------------------------------- /transport/internet/tls/config_other.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package tls 5 | 6 | import ( 7 | "crypto/x509" 8 | "sync" 9 | 10 | "github.com/xtls/xray-core/common/errors" 11 | ) 12 | 13 | type rootCertsCache struct { 14 | sync.Mutex 15 | pool *x509.CertPool 16 | } 17 | 18 | func (c *rootCertsCache) load() (*x509.CertPool, error) { 19 | c.Lock() 20 | defer c.Unlock() 21 | 22 | if c.pool != nil { 23 | return c.pool, nil 24 | } 25 | 26 | pool, err := x509.SystemCertPool() 27 | if err != nil { 28 | return nil, err 29 | } 30 | c.pool = pool 31 | return pool, nil 32 | } 33 | 34 | var rootCerts rootCertsCache 35 | 36 | func (c *Config) getCertPool() (*x509.CertPool, error) { 37 | if c.DisableSystemRoot { 38 | return c.loadSelfCertPool() 39 | } 40 | 41 | if len(c.Certificate) == 0 { 42 | return rootCerts.load() 43 | } 44 | 45 | pool, err := x509.SystemCertPool() 46 | if err != nil { 47 | return nil, errors.New("system root").AtWarning().Base(err) 48 | } 49 | for _, cert := range c.Certificate { 50 | if !pool.AppendCertsFromPEM(cert.Certificate) { 51 | return nil, errors.New("append cert to root").AtWarning().Base(err) 52 | } 53 | } 54 | return pool, nil 55 | } 56 | -------------------------------------------------------------------------------- /app/proxyman/outbound/uot.go: -------------------------------------------------------------------------------- 1 | package outbound 2 | 3 | import ( 4 | "context" 5 | "os" 6 | 7 | "github.com/sagernet/sing/common/uot" 8 | "github.com/xtls/xray-core/common/errors" 9 | "github.com/xtls/xray-core/common/net" 10 | "github.com/xtls/xray-core/transport/internet" 11 | "github.com/xtls/xray-core/transport/internet/stat" 12 | ) 13 | 14 | func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) { 15 | if dest.Address == nil { 16 | return nil, errors.New("nil destination address") 17 | } 18 | if !dest.Address.Family().IsDomain() { 19 | return nil, os.ErrInvalid 20 | } 21 | var uotVersion int 22 | if dest.Address.Domain() == uot.MagicAddress { 23 | uotVersion = uot.Version 24 | } else if dest.Address.Domain() == uot.LegacyMagicAddress { 25 | uotVersion = uot.LegacyVersion 26 | } else { 27 | return nil, os.ErrInvalid 28 | } 29 | packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings) 30 | if err != nil { 31 | return nil, errors.New("unable to listen socket").Base(err) 32 | } 33 | conn := uot.NewServerConn(packetConn, uotVersion) 34 | return h.getStatCouterConnection(conn), nil 35 | } 36 | -------------------------------------------------------------------------------- /common/crypto/benchmark_test.go: -------------------------------------------------------------------------------- 1 | package crypto_test 2 | 3 | import ( 4 | "crypto/cipher" 5 | "testing" 6 | 7 | . "github.com/xtls/xray-core/common/crypto" 8 | ) 9 | 10 | const benchSize = 1024 * 1024 11 | 12 | func benchmarkStream(b *testing.B, c cipher.Stream) { 13 | b.SetBytes(benchSize) 14 | input := make([]byte, benchSize) 15 | output := make([]byte, benchSize) 16 | b.ResetTimer() 17 | for i := 0; i < b.N; i++ { 18 | c.XORKeyStream(output, input) 19 | } 20 | } 21 | 22 | func BenchmarkChaCha20(b *testing.B) { 23 | key := make([]byte, 32) 24 | nonce := make([]byte, 8) 25 | c := NewChaCha20Stream(key, nonce) 26 | benchmarkStream(b, c) 27 | } 28 | 29 | func BenchmarkChaCha20IETF(b *testing.B) { 30 | key := make([]byte, 32) 31 | nonce := make([]byte, 12) 32 | c := NewChaCha20Stream(key, nonce) 33 | benchmarkStream(b, c) 34 | } 35 | 36 | func BenchmarkAESEncryption(b *testing.B) { 37 | key := make([]byte, 32) 38 | iv := make([]byte, 16) 39 | c := NewAesEncryptionStream(key, iv) 40 | 41 | benchmarkStream(b, c) 42 | } 43 | 44 | func BenchmarkAESDecryption(b *testing.B) { 45 | key := make([]byte, 32) 46 | iv := make([]byte, 16) 47 | c := NewAesDecryptionStream(key, iv) 48 | 49 | benchmarkStream(b, c) 50 | } 51 | -------------------------------------------------------------------------------- /common/buf/io_test.go: -------------------------------------------------------------------------------- 1 | package buf_test 2 | 3 | import ( 4 | "crypto/tls" 5 | "io" 6 | "testing" 7 | 8 | . "github.com/xtls/xray-core/common/buf" 9 | "github.com/xtls/xray-core/common/net" 10 | "github.com/xtls/xray-core/testing/servers/tcp" 11 | ) 12 | 13 | func TestWriterCreation(t *testing.T) { 14 | tcpServer := tcp.Server{} 15 | dest, err := tcpServer.Start() 16 | if err != nil { 17 | t.Fatal("failed to start tcp server: ", err) 18 | } 19 | defer tcpServer.Close() 20 | 21 | conn, err := net.Dial("tcp", dest.NetAddr()) 22 | if err != nil { 23 | t.Fatal("failed to dial a TCP connection: ", err) 24 | } 25 | defer conn.Close() 26 | 27 | { 28 | writer := NewWriter(conn) 29 | if _, ok := writer.(*BufferToBytesWriter); !ok { 30 | t.Fatal("writer is not a BufferToBytesWriter") 31 | } 32 | 33 | writer2 := NewWriter(writer.(io.Writer)) 34 | if writer2 != writer { 35 | t.Fatal("writer is not reused") 36 | } 37 | } 38 | 39 | tlsConn := tls.Client(conn, &tls.Config{ 40 | InsecureSkipVerify: true, 41 | }) 42 | defer tlsConn.Close() 43 | 44 | { 45 | writer := NewWriter(tlsConn) 46 | if _, ok := writer.(*SequentialWriter); !ok { 47 | t.Fatal("writer is not a SequentialWriter") 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /proxy/freedom/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.proxy.freedom; 4 | option csharp_namespace = "Xray.Proxy.Freedom"; 5 | option go_package = "github.com/xtls/xray-core/proxy/freedom"; 6 | option java_package = "com.xray.proxy.freedom"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | import "transport/internet/config.proto"; 11 | 12 | message DestinationOverride { 13 | xray.common.protocol.ServerEndpoint server = 1; 14 | } 15 | 16 | message Fragment { 17 | uint64 packets_from = 1; 18 | uint64 packets_to = 2; 19 | uint64 length_min = 3; 20 | uint64 length_max = 4; 21 | uint64 interval_min = 5; 22 | uint64 interval_max = 6; 23 | uint64 max_split_min = 7; 24 | uint64 max_split_max = 8; 25 | } 26 | message Noise { 27 | uint64 length_min = 1; 28 | uint64 length_max = 2; 29 | uint64 delay_min = 3; 30 | uint64 delay_max = 4; 31 | bytes packet = 5; 32 | string apply_to = 6; 33 | } 34 | 35 | message Config { 36 | xray.transport.internet.DomainStrategy domain_strategy = 1; 37 | DestinationOverride destination_override = 3; 38 | uint32 user_level = 4; 39 | Fragment fragment = 5; 40 | uint32 proxy_protocol = 6; 41 | repeated Noise noises = 7; 42 | } 43 | -------------------------------------------------------------------------------- /common/platform/filesystem/file.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/xtls/xray-core/common/buf" 9 | "github.com/xtls/xray-core/common/platform" 10 | ) 11 | 12 | type FileReaderFunc func(path string) (io.ReadCloser, error) 13 | 14 | var NewFileReader FileReaderFunc = func(path string) (io.ReadCloser, error) { 15 | return os.Open(path) 16 | } 17 | 18 | func ReadFile(path string) ([]byte, error) { 19 | reader, err := NewFileReader(path) 20 | if err != nil { 21 | return nil, err 22 | } 23 | defer reader.Close() 24 | 25 | return buf.ReadAllToBytes(reader) 26 | } 27 | 28 | func ReadAsset(file string) ([]byte, error) { 29 | return ReadFile(platform.GetAssetLocation(file)) 30 | } 31 | 32 | func ReadCert(file string) ([]byte, error) { 33 | if filepath.IsAbs(file) { 34 | return ReadFile(file) 35 | } 36 | return ReadFile(platform.GetCertLocation(file)) 37 | } 38 | 39 | func CopyFile(dst string, src string) error { 40 | bytes, err := ReadFile(src) 41 | if err != nil { 42 | return err 43 | } 44 | f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0o644) 45 | if err != nil { 46 | return err 47 | } 48 | defer f.Close() 49 | 50 | _, err = f.Write(bytes) 51 | return err 52 | } 53 | -------------------------------------------------------------------------------- /transport/internet/splithttp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.transport.internet.splithttp; 4 | option csharp_namespace = "Xray.Transport.Internet.SplitHttp"; 5 | option go_package = "github.com/xtls/xray-core/transport/internet/splithttp"; 6 | option java_package = "com.xray.transport.internet.splithttp"; 7 | option java_multiple_files = true; 8 | 9 | import "transport/internet/config.proto"; 10 | 11 | message RangeConfig { 12 | int32 from = 1; 13 | int32 to = 2; 14 | } 15 | 16 | message XmuxConfig { 17 | RangeConfig maxConcurrency = 1; 18 | RangeConfig maxConnections = 2; 19 | RangeConfig cMaxReuseTimes = 3; 20 | RangeConfig hMaxRequestTimes = 4; 21 | RangeConfig hMaxReusableSecs = 5; 22 | int64 hKeepAlivePeriod = 6; 23 | } 24 | 25 | message Config { 26 | string host = 1; 27 | string path = 2; 28 | string mode = 3; 29 | map headers = 4; 30 | RangeConfig xPaddingBytes = 5; 31 | bool noGRPCHeader = 6; 32 | bool noSSEHeader = 7; 33 | RangeConfig scMaxEachPostBytes = 8; 34 | RangeConfig scMinPostsIntervalMs = 9; 35 | int64 scMaxBufferedPosts = 10; 36 | RangeConfig scStreamUpServerSecs = 11; 37 | XmuxConfig xmux = 12; 38 | xray.transport.internet.StreamConfig downloadSettings = 13; 39 | } 40 | -------------------------------------------------------------------------------- /common/type.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "context" 5 | "reflect" 6 | 7 | "github.com/xtls/xray-core/common/errors" 8 | ) 9 | 10 | // ConfigCreator is a function to create an object by a config. 11 | type ConfigCreator func(ctx context.Context, config interface{}) (interface{}, error) 12 | 13 | var typeCreatorRegistry = make(map[reflect.Type]ConfigCreator) 14 | 15 | // RegisterConfig registers a global config creator. The config can be nil but must have a type. 16 | func RegisterConfig(config interface{}, configCreator ConfigCreator) error { 17 | configType := reflect.TypeOf(config) 18 | if _, found := typeCreatorRegistry[configType]; found { 19 | return errors.New(configType.Name() + " is already registered").AtError() 20 | } 21 | typeCreatorRegistry[configType] = configCreator 22 | return nil 23 | } 24 | 25 | // CreateObject creates an object by its config. The config type must be registered through RegisterConfig(). 26 | func CreateObject(ctx context.Context, config interface{}) (interface{}, error) { 27 | configType := reflect.TypeOf(config) 28 | creator, found := typeCreatorRegistry[configType] 29 | if !found { 30 | return nil, errors.New(configType.String() + " is not registered").AtError() 31 | } 32 | return creator(ctx, config) 33 | } 34 | -------------------------------------------------------------------------------- /transport/internet/header_test.go: -------------------------------------------------------------------------------- 1 | package internet_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/xtls/xray-core/common" 7 | . "github.com/xtls/xray-core/transport/internet" 8 | "github.com/xtls/xray-core/transport/internet/headers/noop" 9 | "github.com/xtls/xray-core/transport/internet/headers/srtp" 10 | "github.com/xtls/xray-core/transport/internet/headers/utp" 11 | "github.com/xtls/xray-core/transport/internet/headers/wechat" 12 | "github.com/xtls/xray-core/transport/internet/headers/wireguard" 13 | ) 14 | 15 | func TestAllHeadersLoadable(t *testing.T) { 16 | testCases := []struct { 17 | Input interface{} 18 | Size int32 19 | }{ 20 | { 21 | Input: new(noop.Config), 22 | Size: 0, 23 | }, 24 | { 25 | Input: new(srtp.Config), 26 | Size: 4, 27 | }, 28 | { 29 | Input: new(utp.Config), 30 | Size: 4, 31 | }, 32 | { 33 | Input: new(wechat.VideoConfig), 34 | Size: 13, 35 | }, 36 | { 37 | Input: new(wireguard.WireguardConfig), 38 | Size: 4, 39 | }, 40 | } 41 | 42 | for _, testCase := range testCases { 43 | header, err := CreatePacketHeader(testCase.Input) 44 | common.Must(err) 45 | if header.Size() != testCase.Size { 46 | t.Error("expected size ", testCase.Size, " but got ", header.Size()) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/crypto/chunk_test.go: -------------------------------------------------------------------------------- 1 | package crypto_test 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | 8 | "github.com/xtls/xray-core/common" 9 | "github.com/xtls/xray-core/common/buf" 10 | . "github.com/xtls/xray-core/common/crypto" 11 | ) 12 | 13 | func TestChunkStreamIO(t *testing.T) { 14 | cache := bytes.NewBuffer(make([]byte, 0, 8192)) 15 | 16 | writer := NewChunkStreamWriter(PlainChunkSizeParser{}, cache) 17 | reader := NewChunkStreamReader(PlainChunkSizeParser{}, cache) 18 | 19 | b := buf.New() 20 | b.WriteString("abcd") 21 | common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b})) 22 | 23 | b = buf.New() 24 | b.WriteString("efg") 25 | common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b})) 26 | 27 | common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{})) 28 | 29 | if cache.Len() != 13 { 30 | t.Fatalf("Cache length is %d, want 13", cache.Len()) 31 | } 32 | 33 | mb, err := reader.ReadMultiBuffer() 34 | common.Must(err) 35 | 36 | if s := mb.String(); s != "abcd" { 37 | t.Error("content: ", s) 38 | } 39 | 40 | mb, err = reader.ReadMultiBuffer() 41 | common.Must(err) 42 | 43 | if s := mb.String(); s != "efg" { 44 | t.Error("content: ", s) 45 | } 46 | 47 | _, err = reader.ReadMultiBuffer() 48 | if err != io.EOF { 49 | t.Error("error: ", err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/policy/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package xray.app.policy; 4 | option csharp_namespace = "Xray.App.Policy"; 5 | option go_package = "github.com/xtls/xray-core/app/policy"; 6 | option java_package = "com.xray.app.policy"; 7 | option java_multiple_files = true; 8 | 9 | message Second { 10 | uint32 value = 1; 11 | } 12 | 13 | message Policy { 14 | // Timeout is a message for timeout settings in various stages, in seconds. 15 | message Timeout { 16 | Second handshake = 1; 17 | Second connection_idle = 2; 18 | Second uplink_only = 3; 19 | Second downlink_only = 4; 20 | } 21 | 22 | message Stats { 23 | bool user_uplink = 1; 24 | bool user_downlink = 2; 25 | bool user_online = 3; 26 | } 27 | 28 | message Buffer { 29 | // Buffer size per connection, in bytes. -1 for unlimited buffer. 30 | int32 connection = 1; 31 | } 32 | 33 | Timeout timeout = 1; 34 | Stats stats = 2; 35 | Buffer buffer = 3; 36 | } 37 | 38 | message SystemPolicy { 39 | message Stats { 40 | bool inbound_uplink = 1; 41 | bool inbound_downlink = 2; 42 | bool outbound_uplink = 3; 43 | bool outbound_downlink = 4; 44 | } 45 | 46 | Stats stats = 1; 47 | } 48 | 49 | message Config { 50 | map level = 1; 51 | SystemPolicy system = 2; 52 | } 53 | -------------------------------------------------------------------------------- /testing/coverage/coverall2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | COVERAGE_FILE=${PWD}/coverage.txt 4 | COV_SORTED=${PWD}/coverallsorted.out 5 | 6 | touch "$COVERAGE_FILE" 7 | 8 | function test_package { 9 | DIR=".$1" 10 | DEP=$(go list -f '{{ join .Deps "\n" }}' "$DIR" | grep xray | tr '\n' ',') 11 | DEP=${DEP}$DIR 12 | RND_NAME=$(openssl rand -hex 16) 13 | COV_PROFILE=${RND_NAME}.out 14 | go test -coverprofile="$COV_PROFILE" -coverpkg="$DEP" "$DIR" || return 15 | } 16 | 17 | TEST_FILES=(./*_test.go) 18 | if [ -f "${TEST_FILES[0]}" ]; then 19 | test_package "" 20 | fi 21 | 22 | # shellcheck disable=SC2044 23 | for DIR in $(find ./* -type d ! -path "*.git*" ! -path "*vendor*" ! -path "*external*"); do 24 | TEST_FILES=("$DIR"/*_test.go) 25 | if [ -f "${TEST_FILES[0]}" ]; then 26 | test_package "/$DIR" 27 | fi 28 | done 29 | 30 | # merge out 31 | while IFS= read -r -d '' OUT_FILE 32 | do 33 | echo "Merging file ${OUT_FILE}" 34 | < "${OUT_FILE}" grep -v "mode: set" >> "$COVERAGE_FILE" 35 | done < <(find ./* -name "*.out" -print0) 36 | 37 | < "$COVERAGE_FILE" sort -t: -k1 | grep -vw "testing" | grep -v ".pb.go" | grep -vw "vendor" | grep -vw "external" > "$COV_SORTED" 38 | echo "mode: set" | cat - "${COV_SORTED}" > "${COVERAGE_FILE}" 39 | 40 | bash <(curl -s https://codecov.io/bash) || echo 'Codecov failed to upload' -------------------------------------------------------------------------------- /common/serial/string_test.go: -------------------------------------------------------------------------------- 1 | package serial_test 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | . "github.com/xtls/xray-core/common/serial" 9 | ) 10 | 11 | func TestToString(t *testing.T) { 12 | s := "a" 13 | data := []struct { 14 | Value interface{} 15 | String string 16 | }{ 17 | {Value: s, String: s}, 18 | {Value: &s, String: s}, 19 | {Value: errors.New("t"), String: "t"}, 20 | {Value: []byte{'b', 'c'}, String: "[98 99]"}, 21 | } 22 | 23 | for _, c := range data { 24 | if r := cmp.Diff(ToString(c.Value), c.String); r != "" { 25 | t.Error(r) 26 | } 27 | } 28 | } 29 | 30 | func TestConcat(t *testing.T) { 31 | testCases := []struct { 32 | Input []interface{} 33 | Output string 34 | }{ 35 | { 36 | Input: []interface{}{ 37 | "a", "b", 38 | }, 39 | Output: "ab", 40 | }, 41 | } 42 | 43 | for _, testCase := range testCases { 44 | actual := Concat(testCase.Input...) 45 | if actual != testCase.Output { 46 | t.Error("Unexpected output: ", actual, " but want: ", testCase.Output) 47 | } 48 | } 49 | } 50 | 51 | func BenchmarkConcat(b *testing.B) { 52 | input := []interface{}{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"} 53 | 54 | b.ReportAllocs() 55 | for i := 0; i < b.N; i++ { 56 | _ = Concat(input...) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /transport/internet/splithttp/connection.go: -------------------------------------------------------------------------------- 1 | package splithttp 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "time" 7 | ) 8 | 9 | type splitConn struct { 10 | writer io.WriteCloser 11 | reader io.ReadCloser 12 | remoteAddr net.Addr 13 | localAddr net.Addr 14 | onClose func() 15 | } 16 | 17 | func (c *splitConn) Write(b []byte) (int, error) { 18 | return c.writer.Write(b) 19 | } 20 | 21 | func (c *splitConn) Read(b []byte) (int, error) { 22 | return c.reader.Read(b) 23 | } 24 | 25 | func (c *splitConn) Close() error { 26 | if c.onClose != nil { 27 | c.onClose() 28 | } 29 | 30 | err := c.writer.Close() 31 | err2 := c.reader.Close() 32 | if err != nil { 33 | return err 34 | } 35 | 36 | if err2 != nil { 37 | return err 38 | } 39 | 40 | return nil 41 | } 42 | 43 | func (c *splitConn) LocalAddr() net.Addr { 44 | return c.localAddr 45 | } 46 | 47 | func (c *splitConn) RemoteAddr() net.Addr { 48 | return c.remoteAddr 49 | } 50 | 51 | func (c *splitConn) SetDeadline(t time.Time) error { 52 | // TODO cannot do anything useful 53 | return nil 54 | } 55 | 56 | func (c *splitConn) SetReadDeadline(t time.Time) error { 57 | // TODO cannot do anything useful 58 | return nil 59 | } 60 | 61 | func (c *splitConn) SetWriteDeadline(t time.Time) error { 62 | // TODO cannot do anything useful 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /proxy/blackhole/config.go: -------------------------------------------------------------------------------- 1 | package blackhole 2 | 3 | import ( 4 | "github.com/xtls/xray-core/common" 5 | "github.com/xtls/xray-core/common/buf" 6 | ) 7 | 8 | const ( 9 | http403response = `HTTP/1.1 403 Forbidden 10 | Connection: close 11 | Cache-Control: max-age=3600, public 12 | Content-Length: 0 13 | 14 | 15 | ` 16 | ) 17 | 18 | // ResponseConfig is the configuration for blackhole responses. 19 | type ResponseConfig interface { 20 | // WriteTo writes a predefined response to the specified buffer. 21 | WriteTo(buf.Writer) int32 22 | } 23 | 24 | // WriteTo implements ResponseConfig.WriteTo(). 25 | func (*NoneResponse) WriteTo(buf.Writer) int32 { return 0 } 26 | 27 | // WriteTo implements ResponseConfig.WriteTo(). 28 | func (*HTTPResponse) WriteTo(writer buf.Writer) int32 { 29 | b := buf.New() 30 | common.Must2(b.WriteString(http403response)) 31 | n := b.Len() 32 | writer.WriteMultiBuffer(buf.MultiBuffer{b}) 33 | return n 34 | } 35 | 36 | // GetInternalResponse converts response settings from proto to internal data structure. 37 | func (c *Config) GetInternalResponse() (ResponseConfig, error) { 38 | if c.GetResponse() == nil { 39 | return new(NoneResponse), nil 40 | } 41 | 42 | config, err := c.GetResponse().GetInstance() 43 | if err != nil { 44 | return nil, err 45 | } 46 | return config.(ResponseConfig), nil 47 | } 48 | -------------------------------------------------------------------------------- /main/commands/all/mldsa65.go: -------------------------------------------------------------------------------- 1 | package all 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/base64" 6 | "fmt" 7 | 8 | "github.com/cloudflare/circl/sign/mldsa/mldsa65" 9 | "github.com/xtls/xray-core/main/commands/base" 10 | ) 11 | 12 | var cmdMLDSA65 = &base.Command{ 13 | UsageLine: `{{.Exec}} mldsa65 [-i "seed (base64.RawURLEncoding)"]`, 14 | Short: `Generate key pair for ML-DSA-65 post-quantum signature (REALITY)`, 15 | Long: ` 16 | Generate key pair for ML-DSA-65 post-quantum signature (REALITY). 17 | 18 | Random: {{.Exec}} mldsa65 19 | 20 | From seed: {{.Exec}} mldsa65 -i "seed (base64.RawURLEncoding)" 21 | `, 22 | } 23 | 24 | func init() { 25 | cmdMLDSA65.Run = executeMLDSA65 // break init loop 26 | } 27 | 28 | var input_mldsa65 = cmdMLDSA65.Flag.String("i", "", "") 29 | 30 | func executeMLDSA65(cmd *base.Command, args []string) { 31 | var seed [32]byte 32 | if len(*input_mldsa65) > 0 { 33 | s, _ := base64.RawURLEncoding.DecodeString(*input_mldsa65) 34 | if len(s) != 32 { 35 | fmt.Println("Invalid length of ML-DSA-65 seed.") 36 | return 37 | } 38 | seed = [32]byte(s) 39 | } else { 40 | rand.Read(seed[:]) 41 | } 42 | pub, _ := mldsa65.NewKeyFromSeed(&seed) 43 | fmt.Printf("Seed: %v\nVerify: %v\n", 44 | base64.RawURLEncoding.EncodeToString(seed[:]), 45 | base64.RawURLEncoding.EncodeToString(pub.Bytes())) 46 | } 47 | --------------------------------------------------------------------------------