├── .github
├── build
│ └── friendly-filenames.json
└── workflows
│ ├── release.yml
│ └── test.yml
├── LICENSE
├── README.md
├── app
├── app.go
├── commander
│ ├── commander.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── outbound.go
│ └── service.go
├── dispatcher
│ ├── config.pb.go
│ ├── config.proto
│ ├── default.go
│ ├── dispatcher.go
│ ├── errors.generated.go
│ ├── fakednssniffer.go
│ ├── sniffer.go
│ ├── stats.go
│ └── stats_test.go
├── dns
│ ├── config.pb.go
│ ├── config.proto
│ ├── dns.go
│ ├── dnscommon.go
│ ├── dnscommon_test.go
│ ├── dohdns.go
│ ├── errors.generated.go
│ ├── fakedns
│ │ ├── errors.generated.go
│ │ ├── fake.go
│ │ ├── fakedns.go
│ │ ├── fakedns.pb.go
│ │ ├── fakedns.proto
│ │ └── fakedns_test.go
│ ├── hosts.go
│ ├── hosts_test.go
│ ├── nameserver.go
│ ├── nameserver_fakedns.go
│ ├── nameserver_test.go
│ ├── server.go
│ ├── server_test.go
│ └── udpns.go
├── log
│ ├── command
│ │ ├── command.go
│ │ ├── command_test.go
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── config_grpc.pb.go
│ │ └── errors.generated.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── log.go
│ ├── log_creator.go
│ └── log_test.go
├── policy
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── manager.go
│ ├── manager_test.go
│ └── policy.go
├── proxyman
│ ├── command
│ │ ├── command.go
│ │ ├── command.pb.go
│ │ ├── command.proto
│ │ ├── command_grpc.pb.go
│ │ ├── doc.go
│ │ └── errors.generated.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── inbound
│ │ ├── always.go
│ │ ├── dynamic.go
│ │ ├── errors.generated.go
│ │ ├── inbound.go
│ │ └── worker.go
│ └── outbound
│ │ ├── errors.generated.go
│ │ ├── handler.go
│ │ ├── handler_test.go
│ │ └── outbound.go
├── reverse
│ ├── bridge.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── portal.go
│ ├── portal_test.go
│ └── reverse.go
├── router
│ ├── balancing.go
│ ├── command
│ │ ├── command.go
│ │ ├── command.pb.go
│ │ ├── command.proto
│ │ ├── command_grpc.pb.go
│ │ ├── command_test.go
│ │ ├── config.go
│ │ └── errors.generated.go
│ ├── condition.go
│ ├── condition_geoip.go
│ ├── condition_geoip_test.go
│ ├── condition_test.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── router.go
│ └── router_test.go
└── stats
│ ├── channel.go
│ ├── channel_test.go
│ ├── command
│ ├── command.go
│ ├── command.pb.go
│ ├── command.proto
│ ├── command_grpc.pb.go
│ ├── command_test.go
│ └── errors.generated.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── counter.go
│ ├── counter_test.go
│ ├── errors.generated.go
│ ├── stats.go
│ └── stats_test.go
├── common
├── antireplay
│ └── replayfilter.go
├── bitmask
│ ├── byte.go
│ └── byte_test.go
├── blockdns
│ ├── blockdns.go
│ ├── blockdns_other.go
│ ├── blockdns_windows.go
│ ├── errors.generated.go
│ ├── readme.md
│ └── winsys
│ │ ├── constants.go
│ │ ├── helper.go
│ │ ├── syscall_windows.go
│ │ ├── type.go
│ │ ├── winsys.go
│ │ └── zsyscall_windows.go
├── buf
│ ├── buf.go
│ ├── buffer.go
│ ├── buffer_test.go
│ ├── copy.go
│ ├── copy_test.go
│ ├── data
│ │ └── test_MultiBufferReadAllToByte.dat
│ ├── errors.generated.go
│ ├── io.go
│ ├── io_test.go
│ ├── multi_buffer.go
│ ├── multi_buffer_test.go
│ ├── reader.go
│ ├── reader_test.go
│ ├── readv_posix.go
│ ├── readv_reader.go
│ ├── readv_reader_wasm.go
│ ├── readv_test.go
│ ├── readv_unix.go
│ ├── readv_windows.go
│ ├── writer.go
│ └── writer_test.go
├── bytespool
│ └── pool.go
├── cache
│ ├── lru.go
│ └── lru_test.go
├── cmdarg
│ └── cmdarg.go
├── common.go
├── common_test.go
├── crypto
│ ├── aes.go
│ ├── auth.go
│ ├── auth_test.go
│ ├── benchmark_test.go
│ ├── chacha20.go
│ ├── chacha20_test.go
│ ├── chunk.go
│ ├── chunk_test.go
│ ├── crypto.go
│ ├── errors.generated.go
│ ├── internal
│ │ ├── chacha.go
│ │ ├── chacha_core.generated.go
│ │ └── chacha_core_gen.go
│ └── io.go
├── dice
│ ├── dice.go
│ └── dice_test.go
├── errors.generated.go
├── errors
│ ├── errorgen
│ │ └── main.go
│ ├── errors.go
│ ├── errors_test.go
│ └── multi_error.go
├── interfaces.go
├── log
│ ├── access.go
│ ├── dns.go
│ ├── log.go
│ ├── log.pb.go
│ ├── log.proto
│ ├── log_test.go
│ ├── logger.go
│ └── logger_test.go
├── mux
│ ├── client.go
│ ├── client_test.go
│ ├── errors.generated.go
│ ├── frame.go
│ ├── frame_test.go
│ ├── mux.go
│ ├── mux_test.go
│ ├── reader.go
│ ├── server.go
│ ├── session.go
│ ├── session_test.go
│ └── writer.go
├── net
│ ├── address.go
│ ├── address.pb.go
│ ├── address.proto
│ ├── address_test.go
│ ├── cnc
│ │ └── connection.go
│ ├── destination.go
│ ├── destination.pb.go
│ ├── destination.proto
│ ├── destination_test.go
│ ├── errors.generated.go
│ ├── net.go
│ ├── network.go
│ ├── network.pb.go
│ ├── network.proto
│ ├── port.go
│ ├── port.pb.go
│ ├── port.proto
│ ├── port_test.go
│ └── system.go
├── ocsp
│ ├── errors.generated.go
│ └── ocsp.go
├── peer
│ ├── latency.go
│ └── peer.go
├── platform
│ ├── ctlcmd
│ │ ├── attr_other.go
│ │ ├── attr_windows.go
│ │ ├── ctlcmd.go
│ │ └── errors.generated.go
│ ├── filesystem
│ │ └── file.go
│ ├── others.go
│ ├── platform.go
│ ├── platform_test.go
│ └── windows.go
├── protocol
│ ├── account.go
│ ├── address.go
│ ├── address_test.go
│ ├── bittorrent
│ │ └── bittorrent.go
│ ├── context.go
│ ├── dns
│ │ ├── errors.generated.go
│ │ └── io.go
│ ├── errors.generated.go
│ ├── headers.go
│ ├── headers.pb.go
│ ├── headers.proto
│ ├── http
│ │ ├── headers.go
│ │ ├── headers_test.go
│ │ ├── sniff.go
│ │ └── sniff_test.go
│ ├── id.go
│ ├── id_test.go
│ ├── payload.go
│ ├── protocol.go
│ ├── server_picker.go
│ ├── server_picker_test.go
│ ├── server_spec.go
│ ├── server_spec.pb.go
│ ├── server_spec.proto
│ ├── server_spec_test.go
│ ├── time.go
│ ├── time_test.go
│ ├── tls
│ │ ├── cert
│ │ │ ├── .gitignore
│ │ │ ├── cert.go
│ │ │ ├── cert_test.go
│ │ │ ├── errors.generated.go
│ │ │ └── privateKey.go
│ │ ├── sniff.go
│ │ └── sniff_test.go
│ ├── udp
│ │ ├── packet.go
│ │ └── udp.go
│ ├── user.go
│ ├── user.pb.go
│ └── user.proto
├── retry
│ ├── errors.generated.go
│ ├── retry.go
│ └── retry_test.go
├── route
│ ├── errors.generated.go
│ ├── route.go
│ ├── route_darwin.go
│ ├── route_linux.go
│ └── route_windows.go
├── serial
│ ├── serial.go
│ ├── serial_test.go
│ ├── string.go
│ ├── string_test.go
│ ├── typed_message.go
│ ├── typed_message.pb.go
│ ├── typed_message.proto
│ └── typed_message_test.go
├── session
│ ├── context.go
│ └── session.go
├── signal
│ ├── done
│ │ └── done.go
│ ├── notifier.go
│ ├── notifier_test.go
│ ├── pubsub
│ │ ├── pubsub.go
│ │ └── pubsub_test.go
│ ├── semaphore
│ │ └── semaphore.go
│ ├── timer.go
│ └── timer_test.go
├── strmatcher
│ ├── ac_automaton_matcher.go
│ ├── benchmark_test.go
│ ├── domain_matcher.go
│ ├── domain_matcher_test.go
│ ├── full_matcher.go
│ ├── full_matcher_test.go
│ ├── matchers.go
│ ├── matchers_test.go
│ ├── mph_matcher.go
│ ├── strmatcher.go
│ └── strmatcher_test.go
├── task
│ ├── common.go
│ ├── periodic.go
│ ├── periodic_test.go
│ ├── task.go
│ └── task_test.go
├── type.go
├── type_test.go
├── uuid
│ ├── uuid.go
│ └── uuid_test.go
└── xudp
│ └── xudp.go
├── core
├── annotations.go
├── config.go
├── config.pb.go
├── config.proto
├── context.go
├── context_test.go
├── core.go
├── errors.generated.go
├── functions.go
├── functions_test.go
├── mocks.go
├── proto.go
├── xray.go
└── xray_test.go
├── features
├── dns
│ ├── client.go
│ ├── fakedns.go
│ └── localdns
│ │ ├── client.go
│ │ └── errors.generated.go
├── errors.generated.go
├── feature.go
├── inbound
│ └── inbound.go
├── outbound
│ └── outbound.go
├── policy
│ ├── default.go
│ └── policy.go
├── routing
│ ├── context.go
│ ├── dispatcher.go
│ ├── dns
│ │ ├── context.go
│ │ └── errors.generated.go
│ ├── router.go
│ └── session
│ │ └── context.go
└── stats
│ ├── errors.generated.go
│ └── stats.go
├── go.mod
├── go.sum
├── infra
├── conf
│ ├── api.go
│ ├── blackhole.go
│ ├── blackhole_test.go
│ ├── buildable.go
│ ├── common.go
│ ├── common_test.go
│ ├── conf.go
│ ├── dns.go
│ ├── dns_proxy.go
│ ├── dns_proxy_test.go
│ ├── dns_test.go
│ ├── dokodemo.go
│ ├── dokodemo_test.go
│ ├── errors.generated.go
│ ├── fakedns.go
│ ├── freedom.go
│ ├── freedom_test.go
│ ├── general_test.go
│ ├── grpc.go
│ ├── http.go
│ ├── http_test.go
│ ├── init.go
│ ├── json
│ │ ├── reader.go
│ │ └── reader_test.go
│ ├── lint.go
│ ├── loader.go
│ ├── log.go
│ ├── mtproto.go
│ ├── mtproto_test.go
│ ├── policy.go
│ ├── policy_test.go
│ ├── reverse.go
│ ├── reverse_test.go
│ ├── router.go
│ ├── router_test.go
│ ├── serial
│ │ ├── builder.go
│ │ ├── errors.generated.go
│ │ ├── loader.go
│ │ ├── loader_test.go
│ │ └── serial.go
│ ├── shadowsocks.go
│ ├── shadowsocks_test.go
│ ├── socks.go
│ ├── socks_test.go
│ ├── transport.go
│ ├── transport_authenticators.go
│ ├── transport_internet.go
│ ├── transport_test.go
│ ├── trojan.go
│ ├── tun.go
│ ├── vless.go
│ ├── vless_test.go
│ ├── vmess.go
│ ├── vmess_test.go
│ ├── xray.go
│ └── xray_test.go
└── vprotogen
│ └── main.go
├── main
├── commands
│ ├── all
│ │ ├── api
│ │ │ ├── api.go
│ │ │ ├── inbounds_add.go
│ │ │ ├── inbounds_remove.go
│ │ │ ├── logger_restart.go
│ │ │ ├── outbounds_add.go
│ │ │ ├── outbounds_remove.go
│ │ │ ├── shared.go
│ │ │ ├── stats_get.go
│ │ │ ├── stats_query.go
│ │ │ └── stats_sys.go
│ │ ├── commands.go
│ │ ├── convert.go
│ │ ├── errors.generated.go
│ │ ├── tls
│ │ │ ├── cert.go
│ │ │ ├── ping.go
│ │ │ └── tls.go
│ │ └── uuid.go
│ └── base
│ │ ├── command.go
│ │ ├── env.go
│ │ ├── execute.go
│ │ ├── help.go
│ │ └── root.go
├── confloader
│ ├── confloader.go
│ ├── errors.generated.go
│ └── external
│ │ ├── errors.generated.go
│ │ └── external.go
├── distro
│ ├── all
│ │ └── all.go
│ └── debug
│ │ └── debug.go
├── errors.generated.go
├── json
│ ├── errors.generated.go
│ └── json.go
├── main.go
├── main_test.go
├── run.go
├── toml
│ ├── errors.generated.go
│ └── toml.go
├── version.go
├── xray.exe.manifest
└── yaml
│ ├── errors.generated.go
│ └── yaml.go
├── proxy
├── blackhole
│ ├── blackhole.go
│ ├── blackhole_test.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── config_test.go
│ └── errors.generated.go
├── dns
│ ├── config.pb.go
│ ├── config.proto
│ ├── dns.go
│ ├── dns_test.go
│ └── errors.generated.go
├── dokodemo
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── dokodemo.go
│ ├── errors.generated.go
│ ├── fakeudp_linux.go
│ └── fakeudp_other.go
├── freedom
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ └── freedom.go
├── http
│ ├── client.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── http.go
│ └── server.go
├── mtproto
│ ├── auth.go
│ ├── auth_test.go
│ ├── client.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── mtproto.go
│ └── server.go
├── proxy.go
├── shadowsocks
│ ├── client.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── config_test.go
│ ├── errors.generated.go
│ ├── protocol.go
│ ├── protocol_test.go
│ ├── server.go
│ ├── shadowsocks.go
│ └── validator.go
├── socks
│ ├── client.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── protocol.go
│ ├── protocol_test.go
│ ├── server.go
│ └── socks.go
├── trojan
│ ├── client.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── protocol.go
│ ├── protocol_test.go
│ ├── server.go
│ ├── trojan.go
│ └── validator.go
├── tun
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ └── tun.go
├── vless
│ ├── account.go
│ ├── account.pb.go
│ ├── account.proto
│ ├── encoding
│ │ ├── addons.go
│ │ ├── addons.pb.go
│ │ ├── addons.proto
│ │ ├── encoding.go
│ │ ├── encoding_test.go
│ │ └── errors.generated.go
│ ├── errors.generated.go
│ ├── inbound
│ │ ├── config.go
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── errors.generated.go
│ │ └── inbound.go
│ ├── outbound
│ │ ├── config.go
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── errors.generated.go
│ │ └── outbound.go
│ ├── validator.go
│ └── vless.go
└── vmess
│ ├── account.go
│ ├── account.pb.go
│ ├── account.proto
│ ├── aead
│ ├── authid.go
│ ├── authid_test.go
│ ├── consts.go
│ ├── encrypt.go
│ ├── encrypt_test.go
│ └── kdf.go
│ ├── encoding
│ ├── auth.go
│ ├── auth_test.go
│ ├── client.go
│ ├── commands.go
│ ├── commands_test.go
│ ├── encoding.go
│ ├── encoding_test.go
│ ├── errors.generated.go
│ └── server.go
│ ├── errors.generated.go
│ ├── inbound
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ └── inbound.go
│ ├── outbound
│ ├── command.go
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ └── outbound.go
│ ├── validator.go
│ ├── validator_test.go
│ ├── vmess.go
│ └── vmessCtxInterface.go
├── testing
├── coverage
│ ├── coverall
│ └── coverall2
├── mocks
│ ├── dns.go
│ ├── io.go
│ ├── log.go
│ ├── mux.go
│ ├── outbound.go
│ └── proxy.go
├── scenarios
│ ├── command_test.go
│ ├── common.go
│ ├── common_coverage.go
│ ├── common_regular.go
│ ├── dns_test.go
│ ├── dokodemo_test.go
│ ├── feature_test.go
│ ├── http_test.go
│ ├── policy_test.go
│ ├── reverse_test.go
│ ├── shadowsocks_test.go
│ ├── socks_test.go
│ ├── tls_test.go
│ ├── transport_test.go
│ └── vmess_test.go
└── servers
│ ├── http
│ └── http.go
│ ├── tcp
│ ├── port.go
│ └── tcp.go
│ └── udp
│ ├── port.go
│ └── udp.go
└── transport
├── global
├── config.go
├── config.pb.go
└── config.proto
├── internet
├── config.go
├── config.pb.go
├── config.proto
├── connection.go
├── dialer.go
├── dialer_test.go
├── domainsocket
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── dial.go
│ ├── errgen.go
│ ├── errors.generated.go
│ ├── listener.go
│ └── listener_test.go
├── errors.generated.go
├── filelocker.go
├── filelocker_other.go
├── filelocker_windows.go
├── grpc
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── dial.go
│ ├── encoding
│ │ ├── customSeviceName.go
│ │ ├── encoding.go
│ │ ├── errors.generated.go
│ │ ├── hunkconn.go
│ │ ├── multiconn.go
│ │ ├── stream.pb.go
│ │ ├── stream.proto
│ │ └── stream_grpc.pb.go
│ ├── errors.generated.go
│ ├── grpc.go
│ └── hub.go
├── header.go
├── header_test.go
├── headers
│ ├── http
│ │ ├── config.go
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── errors.generated.go
│ │ ├── http.go
│ │ ├── http_test.go
│ │ ├── linkedreadRequest.go
│ │ └── resp.go
│ ├── noop
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ └── noop.go
│ ├── srtp
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── srtp.go
│ │ └── srtp_test.go
│ ├── tls
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── dtls.go
│ │ └── dtls_test.go
│ ├── utp
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── utp.go
│ │ └── utp_test.go
│ ├── wechat
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ ├── wechat.go
│ │ └── wechat_test.go
│ └── wireguard
│ │ ├── config.pb.go
│ │ ├── config.proto
│ │ └── wireguard.go
├── http
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── dialer.go
│ ├── errors.generated.go
│ ├── http.go
│ ├── http_test.go
│ └── hub.go
├── internet.go
├── kcp
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── connection.go
│ ├── connection_test.go
│ ├── crypt.go
│ ├── crypt_test.go
│ ├── cryptreal.go
│ ├── dialer.go
│ ├── errors.generated.go
│ ├── io.go
│ ├── io_test.go
│ ├── kcp.go
│ ├── kcp_test.go
│ ├── listener.go
│ ├── output.go
│ ├── receiving.go
│ ├── segment.go
│ ├── segment_test.go
│ ├── sending.go
│ ├── xor.go
│ ├── xor_amd64.go
│ └── xor_amd64.s
├── memory_settings.go
├── quic
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── conn.go
│ ├── dialer.go
│ ├── errors.generated.go
│ ├── hub.go
│ ├── pool.go
│ ├── quic.go
│ └── quic_test.go
├── sockopt.go
├── sockopt_darwin.go
├── sockopt_freebsd.go
├── sockopt_linux.go
├── sockopt_linux_test.go
├── sockopt_other.go
├── sockopt_test.go
├── sockopt_windows.go
├── system_dialer.go
├── system_dialer_context.go
├── system_listener.go
├── system_listener_test.go
├── tcp
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── dialer.go
│ ├── errors.generated.go
│ ├── hub.go
│ ├── sockopt_freebsd.go
│ ├── sockopt_linux.go
│ ├── sockopt_linux_test.go
│ ├── sockopt_other.go
│ └── tcp.go
├── tcp_hub.go
├── tls
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── config_other.go
│ ├── config_test.go
│ ├── config_windows.go
│ ├── errors.generated.go
│ └── tls.go
├── tunnel
│ ├── config.pb.go
│ ├── config.proto
│ ├── errors.generated.go
│ ├── handler.go
│ ├── listener.go
│ ├── readme.md
│ ├── stack
│ │ ├── endpoint.go
│ │ ├── errors.generated.go
│ │ ├── options.go
│ │ ├── stack.go
│ │ ├── tcp.go
│ │ ├── udp.go
│ │ └── unsafe.go
│ ├── tun.go
│ ├── tun
│ │ ├── errors.generated.go
│ │ ├── tun.go
│ │ ├── tun_darwin.go
│ │ ├── tun_linux.go
│ │ └── tun_windows.go
│ └── udp.go
├── udp
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── dialer.go
│ ├── dispatcher.go
│ ├── dispatcher_test.go
│ ├── errors.generated.go
│ ├── hub.go
│ ├── hub_freebsd.go
│ ├── hub_linux.go
│ ├── hub_other.go
│ └── udp.go
├── websocket
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── connection.go
│ ├── dialer.go
│ ├── dialer.html
│ ├── errors.generated.go
│ ├── hub.go
│ ├── ws.go
│ └── ws_test.go
└── xtls
│ ├── config.go
│ ├── config.pb.go
│ ├── config.proto
│ ├── config_other.go
│ ├── config_test.go
│ ├── config_windows.go
│ ├── errors.generated.go
│ └── xtls.go
├── link.go
└── pipe
├── impl.go
├── pipe.go
├── pipe_test.go
├── reader.go
└── writer.go
/app/app.go:
--------------------------------------------------------------------------------
1 | // Package app contains feature implementations of Xray. The features may be enabled during runtime.
2 | package app
3 |
--------------------------------------------------------------------------------
/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 | // Services that supported by this server. All services must implement Service
16 | // interface.
17 | repeated xray.common.serial.TypedMessage service = 2;
18 | }
19 |
20 | // ReflectionConfig is the placeholder config for ReflectionService.
21 | message ReflectionConfig {}
22 |
--------------------------------------------------------------------------------
/app/commander/errors.generated.go:
--------------------------------------------------------------------------------
1 | package commander
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/dispatcher/dispatcher.go:
--------------------------------------------------------------------------------
1 | package dispatcher
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/app/dispatcher/errors.generated.go:
--------------------------------------------------------------------------------
1 | package dispatcher
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/dns/dns.go:
--------------------------------------------------------------------------------
1 | // Package dns is an implementation of core.DNS feature.
2 | package dns
3 |
4 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
5 |
--------------------------------------------------------------------------------
/app/dns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/dns/fakedns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package fakedns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/dns/fakedns/fakedns.go:
--------------------------------------------------------------------------------
1 | package fakedns
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/app/dns/nameserver.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/xtls/xray-core/common/net"
7 | "github.com/xtls/xray-core/features/dns"
8 | "github.com/xtls/xray-core/features/dns/localdns"
9 | )
10 |
11 | // Client is the interface for DNS client.
12 | type Client interface {
13 | // Name of the Client.
14 | Name() string
15 |
16 | // QueryIP sends IP queries to its configured server.
17 | QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, error)
18 | }
19 |
20 | type LocalNameServer struct {
21 | client *localdns.Client
22 | }
23 |
24 | func (s *LocalNameServer) QueryIP(_ context.Context, domain string, option dns.IPOption) ([]net.IP, error) {
25 | if option.IPv4Enable || option.IPv6Enable {
26 | return s.client.LookupIP(domain, option)
27 | }
28 |
29 | return nil, newError("neither IPv4 nor IPv6 is enabled")
30 | }
31 |
32 | func (s *LocalNameServer) Name() string {
33 | return "localhost"
34 | }
35 |
36 | func NewLocalNameServer() *LocalNameServer {
37 | newError("DNS: created localhost client").AtInfo().WriteToLog()
38 | return &LocalNameServer{
39 | client: localdns.New(),
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/dns/nameserver_fakedns.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/xtls/xray-core/common/net"
7 | "github.com/xtls/xray-core/core"
8 | "github.com/xtls/xray-core/features/dns"
9 | )
10 |
11 | type FakeDNSServer struct {
12 | fakeDNSEngine dns.FakeDNSEngine
13 | }
14 |
15 | func NewFakeDNSServer() *FakeDNSServer {
16 | return &FakeDNSServer{}
17 | }
18 |
19 | func (FakeDNSServer) Name() string {
20 | return "FakeDNS"
21 | }
22 |
23 | func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ dns.IPOption) ([]net.IP, error) {
24 | if f.fakeDNSEngine == nil {
25 | if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
26 | f.fakeDNSEngine = fd
27 | }); err != nil {
28 | return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
29 | }
30 | }
31 | ips := f.fakeDNSEngine.GetFakeIPForDomain(domain)
32 |
33 | netIP := toNetIP(ips)
34 | if netIP == nil {
35 | return nil, newError("Unable to convert IP to net ip").AtError()
36 | }
37 |
38 | newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
39 |
40 | return netIP, nil
41 | }
42 |
--------------------------------------------------------------------------------
/app/dns/nameserver_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 | dns_feature "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_feature.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/log/command/errors.generated.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | }
27 |
--------------------------------------------------------------------------------
/app/log/errors.generated.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/policy/errors.generated.go:
--------------------------------------------------------------------------------
1 | package policy
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/policy/policy.go:
--------------------------------------------------------------------------------
1 | // Package policy is an implementation of policy.Manager feature.
2 | package policy
3 |
4 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
5 |
--------------------------------------------------------------------------------
/app/proxyman/command/doc.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/app/proxyman/command/errors.generated.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/proxyman/config.go:
--------------------------------------------------------------------------------
1 | package proxyman
2 |
3 | func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
4 | if s == nil || s.Concurrency == nil {
5 | return 3
6 | }
7 | return s.Concurrency.Value
8 | }
9 |
10 | func (s *AllocationStrategy) GetRefreshValue() uint32 {
11 | if s == nil || s.Refresh == nil {
12 | return 5
13 | }
14 | return s.Refresh.Value
15 | }
16 |
17 | func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
18 | if c.SniffingSettings != nil {
19 | return c.SniffingSettings
20 | }
21 |
22 | if len(c.DomainOverride) > 0 {
23 | var p []string
24 | for _, kd := range c.DomainOverride {
25 | switch kd {
26 | case KnownProtocols_HTTP:
27 | p = append(p, "http")
28 | case KnownProtocols_TLS:
29 | p = append(p, "tls")
30 | }
31 | }
32 | return &SniffingConfig{
33 | Enabled: true,
34 | DestinationOverride: p,
35 | }
36 | }
37 |
38 | return nil
39 | }
40 |
--------------------------------------------------------------------------------
/app/proxyman/inbound/errors.generated.go:
--------------------------------------------------------------------------------
1 | package inbound
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/proxyman/outbound/errors.generated.go:
--------------------------------------------------------------------------------
1 | package outbound
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | c.Random = make([]byte, randomLength)
13 | io.ReadFull(rand.Reader, c.Random)
14 | }
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/reverse/errors.generated.go:
--------------------------------------------------------------------------------
1 | package reverse
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/router/balancing.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/xtls/xray-core/common/dice"
5 | "github.com/xtls/xray-core/features/outbound"
6 | )
7 |
8 | type BalancingStrategy interface {
9 | PickOutbound([]string) string
10 | }
11 |
12 | type RandomStrategy struct {
13 | }
14 |
15 | func (s *RandomStrategy) PickOutbound(tags []string) string {
16 | n := len(tags)
17 | if n == 0 {
18 | panic("0 tags")
19 | }
20 |
21 | return tags[dice.Roll(n)]
22 | }
23 |
24 | type Balancer struct {
25 | selectors []string
26 | strategy BalancingStrategy
27 | ohm outbound.Manager
28 | }
29 |
30 | func (b *Balancer) PickOutbound() (string, error) {
31 | hs, ok := b.ohm.(outbound.HandlerSelector)
32 | if !ok {
33 | return "", newError("outbound.Manager is not a HandlerSelector")
34 | }
35 | tags := hs.Select(b.selectors)
36 | if len(tags) == 0 {
37 | return "", newError("no available outbounds selected")
38 | }
39 | tag := b.strategy.PickOutbound(tags)
40 | if tag == "" {
41 | return "", newError("balancing strategy returns empty tag")
42 | }
43 | return tag, nil
44 | }
45 |
--------------------------------------------------------------------------------
/app/router/command/errors.generated.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/router/errors.generated.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/app/stats/command/errors.generated.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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("unpexcted 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 |
--------------------------------------------------------------------------------
/app/stats/errors.generated.go:
--------------------------------------------------------------------------------
1 | package stats
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/common/blockdns/blockdns.go:
--------------------------------------------------------------------------------
1 | package blockdns
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/common/blockdns/blockdns_other.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package blockdns
4 |
5 | import "runtime"
6 |
7 | func FixDnsLeakage(tunName string) error {
8 | return newError("unsupported feature for " + runtime.GOOS)
9 | }
10 |
--------------------------------------------------------------------------------
/common/blockdns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package blockdns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/blockdns/readme.md:
--------------------------------------------------------------------------------
1 | Files in package `common/blockdns` are copied from github.com/mellow-io/go-tun2socks, adapted to xray's architecture.
2 |
3 | Author: @eycorsican
4 |
--------------------------------------------------------------------------------
/common/blockdns/winsys/helper.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package winsys
4 |
5 | import (
6 | "os"
7 | "unsafe"
8 |
9 | "golang.org/x/sys/windows"
10 | )
11 |
12 | func CreateDisplayData(name, description string) (*FWPM_DISPLAY_DATA0, error) {
13 | namePtr, err := windows.UTF16PtrFromString(name)
14 | if err != nil {
15 | return nil, err
16 | }
17 |
18 | descriptionPtr, err := windows.UTF16PtrFromString(description)
19 | if err != nil {
20 | return nil, err
21 | }
22 |
23 | return &FWPM_DISPLAY_DATA0{
24 | Name: namePtr,
25 | Description: descriptionPtr,
26 | }, nil
27 | }
28 |
29 | func GetCurrentProcessAppID() (*FWP_BYTE_BLOB, error) {
30 | currentFile, err := os.Executable()
31 | if err != nil {
32 | return nil, err
33 | }
34 |
35 | curFilePtr, err := windows.UTF16PtrFromString(currentFile)
36 | if err != nil {
37 | return nil, err
38 | }
39 |
40 | var appID *FWP_BYTE_BLOB
41 | err = FwpmGetAppIdFromFileName0(curFilePtr, unsafe.Pointer(&appID))
42 | if err != nil {
43 | return nil, err
44 | }
45 | return appID, nil
46 | }
47 |
--------------------------------------------------------------------------------
/common/blockdns/winsys/winsys.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package winsys
4 |
5 | //go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
6 |
--------------------------------------------------------------------------------
/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 |
4 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
5 |
--------------------------------------------------------------------------------
/common/buf/errors.generated.go:
--------------------------------------------------------------------------------
1 | package buf
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/buf/readv_posix.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 | // +build !wasm
3 | // +build !illumos
4 |
5 | package buf
6 |
7 | import (
8 | "syscall"
9 | "unsafe"
10 | )
11 |
12 | type posixReader struct {
13 | iovecs []syscall.Iovec
14 | }
15 |
16 | func (r *posixReader) Init(bs []*Buffer) {
17 | iovecs := r.iovecs
18 | if iovecs == nil {
19 | iovecs = make([]syscall.Iovec, 0, len(bs))
20 | }
21 | for idx, b := range bs {
22 | iovecs = append(iovecs, syscall.Iovec{
23 | Base: &(b.v[0]),
24 | })
25 | iovecs[idx].SetLen(int(Size))
26 | }
27 | r.iovecs = iovecs
28 | }
29 |
30 | func (r *posixReader) Read(fd uintptr) int32 {
31 | n, _, e := syscall.Syscall(syscall.SYS_READV, fd, uintptr(unsafe.Pointer(&r.iovecs[0])), uintptr(len(r.iovecs)))
32 | if e != 0 {
33 | return -1
34 | }
35 | return int32(n)
36 | }
37 |
38 | func (r *posixReader) Clear() {
39 | for idx := range r.iovecs {
40 | r.iovecs[idx].Base = nil
41 | }
42 | r.iovecs = r.iovecs[:0]
43 | }
44 |
45 | func newMultiReader() multiReader {
46 | return &posixReader{}
47 | }
48 |
--------------------------------------------------------------------------------
/common/buf/readv_reader_wasm.go:
--------------------------------------------------------------------------------
1 | // +build wasm
2 |
3 | package buf
4 |
5 | import (
6 | "io"
7 | "syscall"
8 | )
9 |
10 | const useReadv = false
11 |
12 | func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) Reader {
13 | panic("not implemented")
14 | }
15 |
--------------------------------------------------------------------------------
/common/buf/readv_unix.go:
--------------------------------------------------------------------------------
1 | // +build illumos
2 |
3 | package buf
4 |
5 | import "golang.org/x/sys/unix"
6 |
7 | type unixReader struct {
8 | iovs [][]byte
9 | }
10 |
11 | func (r *unixReader) Init(bs []*Buffer) {
12 | iovs := r.iovs
13 | if iovs == nil {
14 | iovs = make([][]byte, 0, len(bs))
15 | }
16 | for _, b := range bs {
17 | iovs = append(iovs, b.v)
18 | }
19 | r.iovs = iovs
20 | }
21 |
22 | func (r *unixReader) Read(fd uintptr) int32 {
23 | n, e := unix.Readv(int(fd), r.iovs)
24 | if e != nil {
25 | return -1
26 | }
27 | return int32(n)
28 | }
29 |
30 | func (r *unixReader) Clear() {
31 | r.iovs = r.iovs[:0]
32 | }
33 |
34 | func newMultiReader() multiReader {
35 | return &unixReader{}
36 | }
37 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
5 |
--------------------------------------------------------------------------------
/common/crypto/errors.generated.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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/errors.generated.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/errors/multi_error.go:
--------------------------------------------------------------------------------
1 | package errors
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | type multiError []error
8 |
9 | func (e multiError) Error() string {
10 | var r strings.Builder
11 | r.WriteString("multierr: ")
12 | for _, err := range e {
13 | r.WriteString(err.Error())
14 | r.WriteString(" | ")
15 | }
16 | return r.String()
17 | }
18 |
19 | func Combine(maybeError ...error) error {
20 | var errs multiError
21 | for _, err := range maybeError {
22 | if err != nil {
23 | errs = append(errs, err)
24 | }
25 | }
26 | if len(errs) == 0 {
27 | return nil
28 | }
29 | return errs
30 | }
31 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/common/log/log_test.go:
--------------------------------------------------------------------------------
1 | package log_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/google/go-cmp/cmp"
7 |
8 | "github.com/xtls/xray-core/common/log"
9 | "github.com/xtls/xray-core/common/net"
10 | )
11 |
12 | type testLogger struct {
13 | value string
14 | }
15 |
16 | func (l *testLogger) Handle(msg log.Message) {
17 | l.value = msg.String()
18 | }
19 |
20 | func TestLogRecord(t *testing.T) {
21 | var logger testLogger
22 | log.RegisterHandler(&logger)
23 |
24 | ip := "8.8.8.8"
25 | log.Record(&log.GeneralMessage{
26 | Severity: log.Severity_Error,
27 | Content: net.ParseAddress(ip),
28 | })
29 |
30 | if diff := cmp.Diff("[Error] "+ip, logger.value); diff != "" {
31 | t.Error(diff)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/common/log/logger_test.go:
--------------------------------------------------------------------------------
1 | package log_test
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "strings"
7 | "testing"
8 | "time"
9 |
10 | "github.com/xtls/xray-core/common"
11 | "github.com/xtls/xray-core/common/buf"
12 | . "github.com/xtls/xray-core/common/log"
13 | )
14 |
15 | func TestFileLogger(t *testing.T) {
16 | f, err := ioutil.TempFile("", "vtest")
17 | common.Must(err)
18 | path := f.Name()
19 | common.Must(f.Close())
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 |
--------------------------------------------------------------------------------
/common/mux/errors.generated.go:
--------------------------------------------------------------------------------
1 | package mux
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/common/mux/mux.go:
--------------------------------------------------------------------------------
1 | package mux
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/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()
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()
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()
43 |
44 | if m.CloseIfNoSession() {
45 | t.Error("able to close")
46 | }
47 | m.Remove(s.ID)
48 | if !m.CloseIfNoSession() {
49 | t.Error("not able to close")
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/net/errors.generated.go:
--------------------------------------------------------------------------------
1 | package net
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
5 |
--------------------------------------------------------------------------------
/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/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 | RawTCP = 1 [deprecated = true];
13 | TCP = 2;
14 | UDP = 3;
15 | UNIX = 4;
16 | }
17 |
18 | // NetworkList is a list of Networks.
19 | message NetworkList { repeated Network network = 1; }
20 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/common/ocsp/errors.generated.go:
--------------------------------------------------------------------------------
1 | package ocsp
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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/peer/peer.go:
--------------------------------------------------------------------------------
1 | package peer
2 |
--------------------------------------------------------------------------------
/common/platform/ctlcmd/attr_other.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package ctlcmd
4 |
5 | import "syscall"
6 |
7 | func getSysProcAttr() *syscall.SysProcAttr {
8 | return nil
9 | }
10 |
--------------------------------------------------------------------------------
/common/platform/ctlcmd/attr_windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package ctlcmd
4 |
5 | import "syscall"
6 |
7 | func getSysProcAttr() *syscall.SysProcAttr {
8 | return &syscall.SysProcAttr{
9 | HideWindow: true,
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/common/platform/ctlcmd/errors.generated.go:
--------------------------------------------------------------------------------
1 | package ctlcmd
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/platform/filesystem/file.go:
--------------------------------------------------------------------------------
1 | package filesystem
2 |
3 | import (
4 | "io"
5 | "os"
6 |
7 | "github.com/xtls/xray-core/common/buf"
8 | "github.com/xtls/xray-core/common/platform"
9 | )
10 |
11 | type FileReaderFunc func(path string) (io.ReadCloser, error)
12 |
13 | var NewFileReader FileReaderFunc = func(path string) (io.ReadCloser, error) {
14 | return os.Open(path)
15 | }
16 |
17 | func ReadFile(path string) ([]byte, error) {
18 | reader, err := NewFileReader(path)
19 | if err != nil {
20 | return nil, err
21 | }
22 | defer reader.Close()
23 |
24 | return buf.ReadAllToBytes(reader)
25 | }
26 |
27 | func ReadAsset(file string) ([]byte, error) {
28 | return ReadFile(platform.GetAssetLocation(file))
29 | }
30 |
31 | func CopyFile(dst string, src string) error {
32 | bytes, err := ReadFile(src)
33 | if err != nil {
34 | return err
35 | }
36 | f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0644)
37 | if err != nil {
38 | return err
39 | }
40 | defer f.Close()
41 |
42 | _, err = f.Write(bytes)
43 | return err
44 | }
45 |
--------------------------------------------------------------------------------
/common/platform/windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package platform
4 |
5 | import "path/filepath"
6 |
7 | func ExpandEnv(s string) string {
8 | // TODO
9 | return s
10 | }
11 |
12 | func LineSeparator() string {
13 | return "\r\n"
14 | }
15 |
16 | func GetToolLocation(file string) string {
17 | const name = "xray.location.tool"
18 | toolPath := EnvFlag{Name: name, AltName: NormalizeEnvName(name)}.GetValue(getExecutableDir)
19 | return filepath.Join(toolPath, file+".exe")
20 | }
21 |
22 | // GetAssetLocation search for `file` in the excutable dir
23 | func GetAssetLocation(file string) string {
24 | const name = "xray.location.asset"
25 | assetPath := NewEnvFlag(name).GetValue(getExecutableDir)
26 | return filepath.Join(assetPath, file)
27 | }
28 |
--------------------------------------------------------------------------------
/common/protocol/account.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | // Account is a user identity used for authentication.
4 | type Account interface {
5 | Equals(Account) bool
6 | }
7 |
8 | // AsAccount is an object can be converted into account.
9 | type AsAccount interface {
10 | AsAccount() (Account, error)
11 | }
12 |
--------------------------------------------------------------------------------
/common/protocol/bittorrent/bittorrent.go:
--------------------------------------------------------------------------------
1 | package bittorrent
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/xtls/xray-core/common"
7 | )
8 |
9 | type SniffHeader struct {
10 | }
11 |
12 | func (h *SniffHeader) Protocol() string {
13 | return "bittorrent"
14 | }
15 |
16 | func (h *SniffHeader) Domain() string {
17 | return ""
18 | }
19 |
20 | var errNotBittorrent = errors.New("not bittorrent header")
21 |
22 | func SniffBittorrent(b []byte) (*SniffHeader, error) {
23 | if len(b) < 20 {
24 | return nil, common.ErrNoClue
25 | }
26 |
27 | if b[0] == 19 && string(b[1:20]) == "BitTorrent protocol" {
28 | return &SniffHeader{}, nil
29 | }
30 |
31 | return nil, errNotBittorrent
32 | }
33 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/common/protocol/dns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/protocol/errors.generated.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | LEGACY = 1;
12 | AUTO = 2;
13 | AES128_GCM = 3;
14 | CHACHA20_POLY1305 = 4;
15 | NONE = 5;
16 | ZERO = 6;
17 | }
18 |
19 | message SecurityConfig {
20 | SecurityType type = 1;
21 | }
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/protocol.go:
--------------------------------------------------------------------------------
1 | package protocol // import "github.com/xtls/xray-core/common/protocol"
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/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 | repeated xray.common.protocol.User user = 3;
16 | }
17 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/protocol/tls/cert/.gitignore:
--------------------------------------------------------------------------------
1 | *.pem
--------------------------------------------------------------------------------
/common/protocol/tls/cert/errors.generated.go:
--------------------------------------------------------------------------------
1 | package cert
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/common/protocol/udp/udp.go:
--------------------------------------------------------------------------------
1 | package udp
2 |
--------------------------------------------------------------------------------
/common/protocol/user.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | func (u *User) GetTypedAccount() (Account, error) {
4 | if u.GetAccount() == nil {
5 | return nil, newError("Account missing").AtWarning()
6 | }
7 |
8 | rawAccount, err := u.Account.GetInstance()
9 | if err != nil {
10 | return nil, err
11 | }
12 | if asAccount, ok := rawAccount.(AsAccount); ok {
13 | return asAccount.AsAccount()
14 | }
15 | if account, ok := rawAccount.(Account); ok {
16 | return account, nil
17 | }
18 | return nil, newError("Unknown account type: ", u.Account.Type)
19 | }
20 |
21 | func (u *User) ToMemoryUser() (*MemoryUser, error) {
22 | account, err := u.GetTypedAccount()
23 | if err != nil {
24 | return nil, err
25 | }
26 | return &MemoryUser{
27 | Account: account,
28 | Email: u.Email,
29 | Level: u.Level,
30 | }, nil
31 | }
32 |
33 | // MemoryUser is a parsed form of User, to reduce number of parsing of Account proto.
34 | type MemoryUser struct {
35 | // Account is the parsed account of the protocol.
36 | Account Account
37 | Email string
38 | Level uint32
39 | }
40 |
--------------------------------------------------------------------------------
/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 procotols.
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/retry/errors.generated.go:
--------------------------------------------------------------------------------
1 | package retry
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/route/errors.generated.go:
--------------------------------------------------------------------------------
1 | package route
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/common/route/route.go:
--------------------------------------------------------------------------------
1 | package route
2 |
3 | //go:generate errorgen
4 |
5 | import (
6 | "github.com/xtls/xray-core/common/net"
7 | "os/exec"
8 | "strings"
9 | )
10 |
11 | type Helper interface {
12 | GetDefaultInterface() (net.IP, string, error)
13 | GetDefaultGateway() (net.IP, error)
14 | SetDefaultInterface(net.IP, interface{}) error
15 | RemoveDefaultInterface(interface{}) error
16 | }
17 |
18 | // GetHelper return RouterHelper for windows
19 | func GetHelper() Helper {
20 | return defaultHelper
21 | }
22 |
23 | type osCommand struct {
24 | name string
25 | arg string
26 | err string
27 | }
28 |
29 | func runOsCommands(command ...osCommand) error {
30 | for _, cmd := range command {
31 | b, err := exec.Command(cmd.name, strings.Split(cmd.arg, " ")...).CombinedOutput()
32 | if err != nil {
33 | return newError(cmd.err + ": " + string(b)).Base(err)
34 | }
35 | }
36 | return nil
37 | }
38 |
--------------------------------------------------------------------------------
/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 coverts 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 |
--------------------------------------------------------------------------------
/common/serial/string.go:
--------------------------------------------------------------------------------
1 | package serial
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | // ToString serialize 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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/common/task/task.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/xtls/xray-core/common/signal/semaphore"
7 | )
8 |
9 | // OnSuccess executes g() after f() returns nil.
10 | func OnSuccess(f func() error, g func() error) func() error {
11 | return func() error {
12 | if err := f(); err != nil {
13 | return err
14 | }
15 | return g()
16 | }
17 | }
18 |
19 | // Run executes a list of tasks in parallel, returns the first error encountered or nil if all tasks pass.
20 | func Run(ctx context.Context, tasks ...func() error) error {
21 | n := len(tasks)
22 | s := semaphore.New(n)
23 | done := make(chan error, 1)
24 |
25 | for _, task := range tasks {
26 | <-s.Wait()
27 | go func(f func() error) {
28 | err := f()
29 | if err == nil {
30 | s.Signal()
31 | return
32 | }
33 |
34 | select {
35 | case done <- err:
36 | default:
37 | }
38 | }(task)
39 | }
40 |
41 | for i := 0; i < n; i++ {
42 | select {
43 | case err := <-done:
44 | return err
45 | case <-ctx.Done():
46 | return ctx.Err()
47 | case <-s.Wait():
48 | }
49 | }
50 |
51 | return nil
52 | }
53 |
--------------------------------------------------------------------------------
/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 | var 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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/core/context.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | // XrayKey is the key type of Instance in Context, exported for test.
8 | type XrayKey int
9 |
10 | const xrayKey XrayKey = 1
11 |
12 | // FromContext returns an Instance from the given context, or nil if the context doesn't contain one.
13 | func FromContext(ctx context.Context) *Instance {
14 | if s, ok := ctx.Value(xrayKey).(*Instance); ok {
15 | return s
16 | }
17 | return nil
18 | }
19 |
20 | // MustFromContext returns an Instance from the given context, or panics if not present.
21 | func MustFromContext(ctx context.Context) *Instance {
22 | x := FromContext(ctx)
23 | if x == nil {
24 | panic("X is not in context.")
25 | }
26 | return x
27 | }
28 |
--------------------------------------------------------------------------------
/core/context_test.go:
--------------------------------------------------------------------------------
1 | package core_test
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | . "github.com/xtls/xray-core/core"
8 | )
9 |
10 | func TestContextPanic(t *testing.T) {
11 | defer func() {
12 | r := recover()
13 | if r == nil {
14 | t.Error("expect panic, but nil")
15 | }
16 | }()
17 |
18 | MustFromContext(context.Background())
19 | }
20 |
--------------------------------------------------------------------------------
/core/errors.generated.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/core/proto.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import "path/filepath"
4 |
5 | //go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go
6 | //go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc
7 | //go:generate go get -v -u github.com/gogo/protobuf/protoc-gen-gofast
8 | //go:generate go install -v github.com/gogo/protobuf/protoc-gen-gofast
9 | //go:generate go run ../infra/vprotogen/main.go -pwd ./..
10 |
11 | // ProtoFilesUsingProtocGenGoFast is the map of Proto files
12 | // that use `protoc-gen-gofast` to generate pb.go files
13 | var ProtoFilesUsingProtocGenGoFast = map[string]bool{filepath.Join("proxy", "vless", "encoding", "addons.proto"): true}
14 |
--------------------------------------------------------------------------------
/features/dns/fakedns.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import (
4 | gonet "net"
5 |
6 | "github.com/xtls/xray-core/common/net"
7 | "github.com/xtls/xray-core/features"
8 | )
9 |
10 | type FakeDNSEngine interface {
11 | features.Feature
12 | GetFakeIPForDomain(domain string) []net.Address
13 | GetDomainFromFakeDNS(ip net.Address) string
14 | GetFakeIPRange() *gonet.IPNet
15 | }
16 |
17 | var FakeIPPool = "198.18.0.0/16"
18 |
--------------------------------------------------------------------------------
/features/dns/localdns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package localdns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/features/errors.generated.go:
--------------------------------------------------------------------------------
1 | package features
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/features/feature.go:
--------------------------------------------------------------------------------
1 | package features
2 |
3 | import "github.com/xtls/xray-core/common"
4 |
5 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
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 |
14 | // PrintDeprecatedFeatureWarning prints a warning for deprecated feature.
15 | func PrintDeprecatedFeatureWarning(feature string) {
16 | newError("You are using a deprecated feature: " + feature + ". Please update your config file with latest configuration format, or update your client software.").WriteToLog()
17 | }
18 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
21 |
22 | // DispatcherType returns the type of Dispatcher interface. Can be used to implement common.HasType.
23 | //
24 | // xray:api:stable
25 | func DispatcherType() interface{} {
26 | return (*Dispatcher)(nil)
27 | }
28 |
--------------------------------------------------------------------------------
/features/routing/dns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/features/stats/errors.generated.go:
--------------------------------------------------------------------------------
1 | package stats
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/infra/conf/buildable.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import "github.com/golang/protobuf/proto"
4 |
5 | type Buildable interface {
6 | Build() (proto.Message, error)
7 | }
8 |
--------------------------------------------------------------------------------
/infra/conf/conf.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/infra/conf/dns_proxy.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import (
4 | "github.com/golang/protobuf/proto"
5 | "github.com/xtls/xray-core/common/net"
6 | "github.com/xtls/xray-core/proxy/dns"
7 | )
8 |
9 | type DNSOutboundConfig struct {
10 | Network Network `json:"network"`
11 | Address *Address `json:"address"`
12 | Port uint16 `json:"port"`
13 | }
14 |
15 | func (c *DNSOutboundConfig) Build() (proto.Message, error) {
16 | config := &dns.Config{
17 | Server: &net.Endpoint{
18 | Network: c.Network.Build(),
19 | Port: uint32(c.Port),
20 | },
21 | }
22 | if c.Address != nil {
23 | config.Server.Address = c.Address.Build()
24 | }
25 | return config, nil
26 | }
27 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/infra/conf/dokodemo.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import (
4 | "github.com/golang/protobuf/proto"
5 | "github.com/xtls/xray-core/proxy/dokodemo"
6 | )
7 |
8 | type DokodemoConfig struct {
9 | Host *Address `json:"address"`
10 | PortValue uint16 `json:"port"`
11 | NetworkList *NetworkList `json:"network"`
12 | TimeoutValue uint32 `json:"timeout"`
13 | Redirect bool `json:"followRedirect"`
14 | UserLevel uint32 `json:"userLevel"`
15 | }
16 |
17 | func (v *DokodemoConfig) Build() (proto.Message, error) {
18 | config := new(dokodemo.Config)
19 | if v.Host != nil {
20 | config.Address = v.Host.Build()
21 | }
22 | config.Port = uint32(v.PortValue)
23 | config.Networks = v.NetworkList.Build()
24 | config.Timeout = v.TimeoutValue
25 | config.FollowRedirect = v.Redirect
26 | config.UserLevel = v.UserLevel
27 | return config, nil
28 | }
29 |
--------------------------------------------------------------------------------
/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 | "timeout": 10,
23 | "followRedirect": true,
24 | "userLevel": 1
25 | }`,
26 | Parser: loadJSON(creator),
27 | Output: &dokodemo.Config{
28 | Address: &net.IPOrDomain{
29 | Address: &net.IPOrDomain_Ip{
30 | Ip: []byte{8, 8, 8, 8},
31 | },
32 | },
33 | Port: 53,
34 | Networks: []net.Network{net.Network_TCP},
35 | Timeout: 10,
36 | FollowRedirect: true,
37 | UserLevel: 1,
38 | },
39 | },
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/infra/conf/errors.generated.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | )
11 |
12 | func TestFreedomConfig(t *testing.T) {
13 | creator := func() Buildable {
14 | return new(FreedomConfig)
15 | }
16 |
17 | runMultiTestCase(t, []TestCase{
18 | {
19 | Input: `{
20 | "domainStrategy": "AsIs",
21 | "timeout": 10,
22 | "redirect": "127.0.0.1:3366",
23 | "userLevel": 1
24 | }`,
25 | Parser: loadJSON(creator),
26 | Output: &freedom.Config{
27 | DomainStrategy: freedom.Config_AS_IS,
28 | Timeout: 10,
29 | DestinationOverride: &freedom.DestinationOverride{
30 | Server: &protocol.ServerEndpoint{
31 | Address: &net.IPOrDomain{
32 | Address: &net.IPOrDomain_Ip{
33 | Ip: []byte{127, 0, 0, 1},
34 | },
35 | },
36 | Port: 3366,
37 | },
38 | },
39 | UserLevel: 1,
40 | },
41 | },
42 | })
43 | }
44 |
--------------------------------------------------------------------------------
/infra/conf/general_test.go:
--------------------------------------------------------------------------------
1 | package conf_test
2 |
3 | import (
4 | "encoding/json"
5 | "testing"
6 |
7 | "github.com/golang/protobuf/proto"
8 | "github.com/xtls/xray-core/common"
9 | . "github.com/xtls/xray-core/infra/conf"
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 |
--------------------------------------------------------------------------------
/infra/conf/grpc.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import (
4 | "github.com/golang/protobuf/proto"
5 |
6 | "github.com/xtls/xray-core/transport/internet/grpc"
7 | )
8 |
9 | type GRPCConfig struct {
10 | ServiceName string `json:"serviceName"`
11 | MultiMode bool `json:"multiMode"`
12 | }
13 |
14 | func (g GRPCConfig) Build() (proto.Message, error) {
15 | return &grpc.Config{ServiceName: g.ServiceName, MultiMode: g.MultiMode}, nil
16 | }
17 |
--------------------------------------------------------------------------------
/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 | "timeout": 10,
19 | "accounts": [
20 | {
21 | "user": "my-username",
22 | "pass": "my-password"
23 | }
24 | ],
25 | "allowTransparent": true,
26 | "userLevel": 1
27 | }`,
28 | Parser: loadJSON(creator),
29 | Output: &http.ServerConfig{
30 | Accounts: map[string]string{
31 | "my-username": "my-password",
32 | },
33 | AllowTransparent: true,
34 | UserLevel: 1,
35 | Timeout: 10,
36 | },
37 | },
38 | })
39 | }
40 |
--------------------------------------------------------------------------------
/infra/conf/init.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | func init() {
4 | RegisterConfigureFilePostProcessingStage("FakeDNS", &FakeDNSPostProcessingStage{})
5 | }
6 |
--------------------------------------------------------------------------------
/infra/conf/lint.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | type ConfigureFilePostProcessingStage interface {
4 | Process(conf *Config) error
5 | }
6 |
7 | var configureFilePostProcessingStages map[string]ConfigureFilePostProcessingStage
8 |
9 | func RegisterConfigureFilePostProcessingStage(name string, stage ConfigureFilePostProcessingStage) {
10 | if configureFilePostProcessingStages == nil {
11 | configureFilePostProcessingStages = make(map[string]ConfigureFilePostProcessingStage)
12 | }
13 | configureFilePostProcessingStages[name] = stage
14 | }
15 |
16 | func PostProcessConfigureFile(conf *Config) error {
17 | for k, v := range configureFilePostProcessingStages {
18 | if err := v.Process(conf); err != nil {
19 | return newError("Rejected by Postprocessing Stage ", k).AtError().Base(err)
20 | }
21 | }
22 | return nil
23 | }
24 |
--------------------------------------------------------------------------------
/infra/conf/mtproto_test.go:
--------------------------------------------------------------------------------
1 | package conf_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/xtls/xray-core/common/protocol"
7 | "github.com/xtls/xray-core/common/serial"
8 | . "github.com/xtls/xray-core/infra/conf"
9 | "github.com/xtls/xray-core/proxy/mtproto"
10 | )
11 |
12 | func TestMTProtoServerConfig(t *testing.T) {
13 | creator := func() Buildable {
14 | return new(MTProtoServerConfig)
15 | }
16 |
17 | runMultiTestCase(t, []TestCase{
18 | {
19 | Input: `{
20 | "users": [{
21 | "email": "love@example.com",
22 | "level": 1,
23 | "secret": "b0cbcef5a486d9636472ac27f8e11a9d"
24 | }]
25 | }`,
26 | Parser: loadJSON(creator),
27 | Output: &mtproto.ServerConfig{
28 | User: []*protocol.User{
29 | {
30 | Email: "love@example.com",
31 | Level: 1,
32 | Account: serial.ToTypedMessage(&mtproto.Account{
33 | Secret: []byte{176, 203, 206, 245, 164, 134, 217, 99, 100, 114, 172, 39, 248, 225, 26, 157},
34 | }),
35 | },
36 | },
37 | },
38 | },
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/serial/errors.generated.go:
--------------------------------------------------------------------------------
1 | package serial
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/infra/conf/serial/serial.go:
--------------------------------------------------------------------------------
1 | package serial
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/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-128-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_128_GCM,
29 | Password: "xray-password",
30 | }),
31 | }},
32 | Network: []net.Network{net.Network_TCP},
33 | },
34 | },
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/infra/conf/tun.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import (
4 | "github.com/golang/protobuf/proto"
5 | "github.com/xtls/xray-core/proxy/tun"
6 | )
7 |
8 | type TunnelConfig struct {
9 | UserLevel uint32 `json:"userLevel"`
10 | }
11 |
12 | func (v *TunnelConfig) Build() (proto.Message, error) {
13 | config := new(tun.Config)
14 | config.UserLevel = v.UserLevel
15 | return config, nil
16 | }
17 |
18 | type TunnelServerConfig struct {
19 | UserLevel uint32 `json:"userLevel"`
20 | }
21 |
22 | func (v *TunnelServerConfig) Build() (proto.Message, error) {
23 | config := new(tun.ServerConfig)
24 | config.UserLevel = v.UserLevel
25 | return config, nil
26 | }
27 |
--------------------------------------------------------------------------------
/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 | cmdAddInbounds,
19 | cmdAddOutbounds,
20 | cmdRemoveInbounds,
21 | cmdRemoveOutbounds,
22 | },
23 | }
24 |
--------------------------------------------------------------------------------
/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 | Arguments:
15 | -s, -server
16 | The API server address. Default 127.0.0.1:8080
17 | -t, -timeout
18 | Timeout seconds to call API. Default 3
19 | `,
20 | Run: executeRestartLogger,
21 | }
22 |
23 | func executeRestartLogger(cmd *base.Command, args []string) {
24 | setSharedFlags(cmd)
25 | cmd.Flag.Parse(args)
26 |
27 | conn, ctx, close := dialAPIServer()
28 | defer close()
29 |
30 | client := logService.NewLoggerServiceClient(conn)
31 | r := &logService.RestartLoggerRequest{}
32 | resp, err := client.RestartLogger(ctx, r)
33 | if err != nil {
34 | base.Fatalf("failed to restart logger: %s", err)
35 | }
36 | showResponese(resp)
37 | }
38 |
--------------------------------------------------------------------------------
/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: "Get system statistics",
12 | Long: `
13 | Get system statistics from Xray.
14 | Arguments:
15 | -s, -server
16 | The API server address. Default 127.0.0.1:8080
17 | -t, -timeout
18 | Timeout seconds to call API. Default 3
19 | `,
20 | Run: executeSysStats,
21 | }
22 |
23 | func executeSysStats(cmd *base.Command, args []string) {
24 | setSharedFlags(cmd)
25 | cmd.Flag.Parse(args)
26 |
27 | conn, ctx, close := dialAPIServer()
28 | defer close()
29 |
30 | client := statsService.NewStatsServiceClient(conn)
31 | r := &statsService.SysStatsRequest{}
32 | resp, err := client.GetSysStats(ctx, r)
33 | if err != nil {
34 | base.Fatalf("failed to get sys stats: %s", err)
35 | }
36 | showResponese(resp)
37 | }
38 |
--------------------------------------------------------------------------------
/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/tls"
6 | "github.com/xtls/xray-core/main/commands/base"
7 | )
8 |
9 | // go:generate go run github.com/xtls/xray-core/common/errors/errorgen
10 |
11 | func init() {
12 | base.RootCommand.Commands = append(
13 | base.RootCommand.Commands,
14 | api.CmdAPI,
15 | //cmdConvert,
16 | tls.CmdTLS,
17 | cmdUUID,
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/main/commands/all/errors.generated.go:
--------------------------------------------------------------------------------
1 | package all
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | },
17 | }
18 |
--------------------------------------------------------------------------------
/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`,
13 | Long: `
14 | Generate UUIDv4 or UUIDv5.
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 |
--------------------------------------------------------------------------------
/main/commands/base/env.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import (
4 | "os"
5 | "path"
6 | )
7 |
8 | // CommandEnvHolder is a struct holds the environment info of commands
9 | type CommandEnvHolder struct {
10 | // Excutable name of current binary
11 | Exec string
12 | // commands column width of current command
13 | CommandsWidth int
14 | }
15 |
16 | // CommandEnv holds the environment info of commands
17 | var CommandEnv CommandEnvHolder
18 |
19 | func init() {
20 | exec, err := os.Executable()
21 | if err != nil {
22 | return
23 | }
24 | CommandEnv.Exec = path.Base(exec)
25 | CommandEnv.Exec = "xray"
26 | }
27 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/main/confloader/confloader.go:
--------------------------------------------------------------------------------
1 | package confloader
2 |
3 | import (
4 | "io"
5 | "os"
6 | )
7 |
8 | type configFileLoader func(string) (io.Reader, error)
9 | type extconfigLoader func([]string, io.Reader) (io.Reader, error)
10 |
11 | var (
12 | EffectiveConfigFileLoader configFileLoader
13 | EffectiveExtConfigLoader extconfigLoader
14 | )
15 |
16 | // LoadConfig reads from a path/url/stdin
17 | // actual work is in external module
18 | func LoadConfig(file string) (io.Reader, error) {
19 | if EffectiveConfigFileLoader == nil {
20 | newError("external config module not loaded, reading from stdin").AtInfo().WriteToLog()
21 | return os.Stdin, nil
22 | }
23 | return EffectiveConfigFileLoader(file)
24 | }
25 |
26 | // LoadExtConfig calls xctl to handle multiple config
27 | // the actual work also in external module
28 | func LoadExtConfig(files []string, reader io.Reader) (io.Reader, error) {
29 | if EffectiveExtConfigLoader == nil {
30 | return nil, newError("external config module not loaded").AtError()
31 | }
32 |
33 | return EffectiveExtConfigLoader(files, reader)
34 | }
35 |
--------------------------------------------------------------------------------
/main/confloader/errors.generated.go:
--------------------------------------------------------------------------------
1 | package confloader
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/main/confloader/external/errors.generated.go:
--------------------------------------------------------------------------------
1 | package external
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/main/errors.generated.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/main/json/errors.generated.go:
--------------------------------------------------------------------------------
1 | package json
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/main/main_test.go:
--------------------------------------------------------------------------------
1 | // +build coveragemain
2 |
3 | package main
4 |
5 | import (
6 | "testing"
7 | )
8 |
9 | func TestRunMainForCoverage(t *testing.T) {
10 | main()
11 | }
12 |
--------------------------------------------------------------------------------
/main/toml/errors.generated.go:
--------------------------------------------------------------------------------
1 | package toml
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/main/xray.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 | Xray
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/main/yaml/errors.generated.go:
--------------------------------------------------------------------------------
1 | package yaml
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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/proxy/blackhole"
11 | "github.com/xtls/xray-core/transport"
12 | "github.com/xtls/xray-core/transport/pipe"
13 | )
14 |
15 | func TestBlackholeHTTPResponse(t *testing.T) {
16 | handler, err := blackhole.New(context.Background(), &blackhole.Config{
17 | Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}),
18 | })
19 | common.Must(err)
20 |
21 | reader, writer := pipe.New(pipe.WithoutSizeLimit())
22 |
23 | var mb buf.MultiBuffer
24 | var rerr error
25 | go func() {
26 | b, e := reader.ReadMultiBuffer()
27 | mb = b
28 | rerr = e
29 | }()
30 |
31 | link := transport.Link{
32 | Reader: reader,
33 | Writer: writer,
34 | }
35 | common.Must(handler.Process(context.Background(), &link, nil))
36 | common.Must(rerr)
37 | if mb.IsEmpty() {
38 | t.Error("expect http response, but nothing")
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/proxy/blackhole/errors.generated.go:
--------------------------------------------------------------------------------
1 | package blackhole
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | }
16 |
--------------------------------------------------------------------------------
/proxy/dns/errors.generated.go:
--------------------------------------------------------------------------------
1 | package dns
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | // List of networks that the Dokodemo accepts.
17 | // Deprecated. Use networks.
18 | xray.common.net.NetworkList network_list = 3 [deprecated = true];
19 | // List of networks that the Dokodemo accepts.
20 | repeated xray.common.net.Network networks = 7;
21 |
22 | uint32 timeout = 4 [deprecated = true];
23 | bool follow_redirect = 5;
24 | uint32 user_level = 6;
25 | }
26 |
--------------------------------------------------------------------------------
/proxy/dokodemo/errors.generated.go:
--------------------------------------------------------------------------------
1 | package dokodemo
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/dokodemo/fakeudp_other.go:
--------------------------------------------------------------------------------
1 | // +build !linux
2 |
3 | package dokodemo
4 |
5 | import (
6 | "fmt"
7 | "net"
8 | )
9 |
10 | func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
11 | return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("!linux")}
12 | }
13 |
--------------------------------------------------------------------------------
/proxy/freedom/config.go:
--------------------------------------------------------------------------------
1 | package freedom
2 |
3 | func (c *Config) useIP() bool {
4 | return c.DomainStrategy == Config_USE_IP || c.DomainStrategy == Config_USE_IP4 || c.DomainStrategy == Config_USE_IP6
5 | }
6 |
--------------------------------------------------------------------------------
/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 |
11 | message DestinationOverride {
12 | xray.common.protocol.ServerEndpoint server = 1;
13 | }
14 |
15 | message Config {
16 | enum DomainStrategy {
17 | AS_IS = 0;
18 | USE_IP = 1;
19 | USE_IP4 = 2;
20 | USE_IP6 = 3;
21 | }
22 | DomainStrategy domain_strategy = 1;
23 | uint32 timeout = 2 [deprecated = true];
24 | DestinationOverride destination_override = 3;
25 | uint32 user_level = 4;
26 | }
27 |
--------------------------------------------------------------------------------
/proxy/freedom/errors.generated.go:
--------------------------------------------------------------------------------
1 | package freedom
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/http/config.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "github.com/xtls/xray-core/common/protocol"
5 | )
6 |
7 | func (a *Account) Equals(another protocol.Account) bool {
8 | if account, ok := another.(*Account); ok {
9 | return a.Username == account.Username
10 | }
11 | return false
12 | }
13 |
14 | func (a *Account) AsAccount() (protocol.Account, error) {
15 | return a, nil
16 | }
17 |
18 | func (sc *ServerConfig) HasAccount(username, password string) bool {
19 | if sc.Accounts == nil {
20 | return false
21 | }
22 |
23 | p, found := sc.Accounts[username]
24 | if !found {
25 | return false
26 | }
27 | return p == password
28 | }
29 |
--------------------------------------------------------------------------------
/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 | uint32 timeout = 1 [deprecated = true];
19 | map accounts = 2;
20 | bool allow_transparent = 3;
21 | uint32 user_level = 4;
22 | }
23 |
24 | // ClientConfig is the protobuf config for HTTP proxy client.
25 | message ClientConfig {
26 | // Sever is a list of HTTP server addresses.
27 | repeated xray.common.protocol.ServerEndpoint server = 1;
28 | }
29 |
--------------------------------------------------------------------------------
/proxy/http/errors.generated.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/http/http.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/proxy/mtproto/config.go:
--------------------------------------------------------------------------------
1 | package mtproto
2 |
3 | import (
4 | "github.com/xtls/xray-core/common/protocol"
5 | )
6 |
7 | func (a *Account) Equals(another protocol.Account) bool {
8 | aa, ok := another.(*Account)
9 | if !ok {
10 | return false
11 | }
12 |
13 | if len(a.Secret) != len(aa.Secret) {
14 | return false
15 | }
16 |
17 | for i, v := range a.Secret {
18 | if v != aa.Secret[i] {
19 | return false
20 | }
21 | }
22 |
23 | return true
24 | }
25 |
--------------------------------------------------------------------------------
/proxy/mtproto/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.proxy.mtproto;
4 | option csharp_namespace = "Xray.Proxy.Mtproto";
5 | option go_package = "github.com/xtls/xray-core/proxy/mtproto";
6 | option java_package = "com.xray.proxy.mtproto";
7 | option java_multiple_files = true;
8 |
9 | import "common/protocol/user.proto";
10 |
11 | message Account {
12 | bytes secret = 1;
13 | }
14 |
15 | message ServerConfig {
16 | // User is a list of users that allowed to connect to this inbound.
17 | // Although this is a repeated field, only the first user is effective for
18 | // now.
19 | repeated xray.common.protocol.User user = 1;
20 | }
21 |
22 | message ClientConfig {}
23 |
--------------------------------------------------------------------------------
/proxy/mtproto/errors.generated.go:
--------------------------------------------------------------------------------
1 | package mtproto
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/mtproto/mtproto.go:
--------------------------------------------------------------------------------
1 | package mtproto
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/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 |
18 | enum CipherType {
19 | UNKNOWN = 0;
20 | AES_128_CFB = 1;
21 | AES_256_CFB = 2;
22 | CHACHA20 = 3;
23 | CHACHA20_IETF = 4;
24 | AES_128_GCM = 5;
25 | AES_256_GCM = 6;
26 | CHACHA20_POLY1305 = 7;
27 | NONE = 8;
28 | }
29 |
30 | message ServerConfig {
31 | repeated xray.common.protocol.User users = 1;
32 | repeated xray.common.net.Network network = 2;
33 | }
34 |
35 | message ClientConfig {
36 | repeated xray.common.protocol.ServerEndpoint server = 1;
37 | }
38 |
--------------------------------------------------------------------------------
/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 |
9 | "github.com/xtls/xray-core/common"
10 | "github.com/xtls/xray-core/common/buf"
11 | "github.com/xtls/xray-core/proxy/shadowsocks"
12 | )
13 |
14 | func TestAEADCipherUDP(t *testing.T) {
15 | rawAccount := &shadowsocks.Account{
16 | CipherType: shadowsocks.CipherType_AES_128_GCM,
17 | Password: "test",
18 | }
19 | account, err := rawAccount.AsAccount()
20 | common.Must(err)
21 |
22 | cipher := account.(*shadowsocks.MemoryAccount).Cipher
23 |
24 | key := make([]byte, cipher.KeySize())
25 | common.Must2(rand.Read(key))
26 |
27 | payload := make([]byte, 1024)
28 | common.Must2(rand.Read(payload))
29 |
30 | b1 := buf.New()
31 | common.Must2(b1.ReadFullFrom(rand.Reader, cipher.IVSize()))
32 | common.Must2(b1.Write(payload))
33 | common.Must(cipher.EncodePacket(key, b1))
34 |
35 | common.Must(cipher.DecodePacket(key, b1))
36 | if diff := cmp.Diff(b1.Bytes(), payload); diff != "" {
37 | t.Error(diff)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/proxy/shadowsocks/errors.generated.go:
--------------------------------------------------------------------------------
1 | package shadowsocks
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
8 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
9 |
--------------------------------------------------------------------------------
/proxy/socks/config.go:
--------------------------------------------------------------------------------
1 | package socks
2 |
3 | import "github.com/xtls/xray-core/common/protocol"
4 |
5 | func (a *Account) Equals(another protocol.Account) bool {
6 | if account, ok := another.(*Account); ok {
7 | return a.Username == account.Username
8 | }
9 | return false
10 | }
11 |
12 | func (a *Account) AsAccount() (protocol.Account, error) {
13 | return a, nil
14 | }
15 |
16 | func (c *ServerConfig) HasAccount(username, password string) bool {
17 | if c.Accounts == nil {
18 | return false
19 | }
20 | storedPassed, found := c.Accounts[username]
21 | if !found {
22 | return false
23 | }
24 | return storedPassed == password
25 | }
26 |
--------------------------------------------------------------------------------
/proxy/socks/errors.generated.go:
--------------------------------------------------------------------------------
1 | package socks
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/socks/socks.go:
--------------------------------------------------------------------------------
1 | // Package socks provides implements of Socks protocol 4, 4a and 5.
2 | package socks
3 |
4 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
5 |
--------------------------------------------------------------------------------
/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 | string flow = 2;
15 | }
16 |
17 | message Fallback {
18 | string name = 1;
19 | string alpn = 2;
20 | string path = 3;
21 | string type = 4;
22 | string dest = 5;
23 | uint64 xver = 6;
24 | }
25 |
26 | message ClientConfig {
27 | repeated xray.common.protocol.ServerEndpoint server = 1;
28 | }
29 |
30 | message ServerConfig {
31 | repeated xray.common.protocol.User users = 1;
32 | repeated Fallback fallbacks = 3;
33 | }
34 |
--------------------------------------------------------------------------------
/proxy/trojan/errors.generated.go:
--------------------------------------------------------------------------------
1 | package trojan
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/trojan/trojan.go:
--------------------------------------------------------------------------------
1 | package trojan
2 |
3 | const (
4 | muxCoolAddress = "v1.mux.cool"
5 | )
6 |
--------------------------------------------------------------------------------
/proxy/tun/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.proxy.tun;
4 | option csharp_namespace = "Xray.Proxy.tun";
5 | option go_package = "github.com/xtls/xray-core/proxy/tun";
6 | option java_package = "com.xray.proxy.tun";
7 | option java_multiple_files = true;
8 |
9 | message Config {
10 | uint32 user_level = 1;
11 | }
12 |
13 | message ServerConfig {
14 | uint32 user_level = 1;
15 | }
16 |
--------------------------------------------------------------------------------
/proxy/tun/errors.generated.go:
--------------------------------------------------------------------------------
1 | package tun
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 Account {
10 | // ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
11 | string id = 1;
12 | // Flow settings. May be "xtls-rprx-direct".
13 | string flow = 2;
14 | // Encryption settings. Only applies to client side, and only accepts "none" for now.
15 | string encryption = 3;
16 | }
17 |
--------------------------------------------------------------------------------
/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/vless/encoding/errors.generated.go:
--------------------------------------------------------------------------------
1 | package encoding
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/vless/errors.generated.go:
--------------------------------------------------------------------------------
1 | package vless
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/vless/inbound/config.go:
--------------------------------------------------------------------------------
1 | package inbound
2 |
--------------------------------------------------------------------------------
/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 | // Decryption settings. Only applies to server side, and only accepts "none"
23 | // for now.
24 | string decryption = 2;
25 | repeated Fallback fallbacks = 3;
26 | }
27 |
--------------------------------------------------------------------------------
/proxy/vless/inbound/errors.generated.go:
--------------------------------------------------------------------------------
1 | package inbound
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/vless/outbound/config.go:
--------------------------------------------------------------------------------
1 | package outbound
2 |
--------------------------------------------------------------------------------
/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 | repeated xray.common.protocol.ServerEndpoint vnext = 1;
13 | }
14 |
--------------------------------------------------------------------------------
/proxy/vless/outbound/errors.generated.go:
--------------------------------------------------------------------------------
1 | package outbound
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
9 |
10 | const (
11 | XRO = "xtls-rprx-origin"
12 | XRD = "xtls-rprx-direct"
13 | XRS = "xtls-rprx-splice"
14 | )
15 |
--------------------------------------------------------------------------------
/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 | // Number of alternative IDs. Client and server must share the same number.
16 | uint32 alter_id = 2;
17 | // Security settings. Only applies to client side.
18 | xray.common.protocol.SecurityConfig security_settings = 3;
19 | // Define tests enabled for this account
20 | string tests_enabled = 4;
21 | }
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/proxy/vmess/encoding/auth_test.go:
--------------------------------------------------------------------------------
1 | package encoding_test
2 |
3 | import (
4 | "crypto/rand"
5 | "testing"
6 |
7 | "github.com/google/go-cmp/cmp"
8 |
9 | "github.com/xtls/xray-core/common"
10 | . "github.com/xtls/xray-core/proxy/vmess/encoding"
11 | )
12 |
13 | func TestFnvAuth(t *testing.T) {
14 | fnvAuth := new(FnvAuthenticator)
15 |
16 | expectedText := make([]byte, 256)
17 | _, err := rand.Read(expectedText)
18 | common.Must(err)
19 |
20 | buffer := make([]byte, 512)
21 | b := fnvAuth.Seal(buffer[:0], nil, expectedText, nil)
22 | b, err = fnvAuth.Open(buffer[:0], nil, b, nil)
23 | common.Must(err)
24 | if r := cmp.Diff(b, expectedText); r != "" {
25 | t.Error(r)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/proxy/vmess/encoding/commands_test.go:
--------------------------------------------------------------------------------
1 | package encoding_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/google/go-cmp/cmp"
7 |
8 | "github.com/xtls/xray-core/common"
9 | "github.com/xtls/xray-core/common/buf"
10 | "github.com/xtls/xray-core/common/protocol"
11 | "github.com/xtls/xray-core/common/uuid"
12 | . "github.com/xtls/xray-core/proxy/vmess/encoding"
13 | )
14 |
15 | func TestSwitchAccount(t *testing.T) {
16 | sa := &protocol.CommandSwitchAccount{
17 | Port: 1234,
18 | ID: uuid.New(),
19 | AlterIds: 1024,
20 | Level: 128,
21 | ValidMin: 16,
22 | }
23 |
24 | buffer := buf.New()
25 | common.Must(MarshalCommand(sa, buffer))
26 |
27 | cmd, err := UnmarshalCommand(1, buffer.BytesFrom(2))
28 | common.Must(err)
29 |
30 | sa2, ok := cmd.(*protocol.CommandSwitchAccount)
31 | if !ok {
32 | t.Fatal("failed to convert command to CommandSwitchAccount")
33 | }
34 | if r := cmp.Diff(sa2, sa); r != "" {
35 | t.Error(r)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/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 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
9 |
10 | const (
11 | Version = byte(1)
12 | )
13 |
14 | var addrParser = protocol.NewAddressParser(
15 | protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
16 | protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
17 | protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),
18 | protocol.PortThenAddress(),
19 | )
20 |
--------------------------------------------------------------------------------
/proxy/vmess/encoding/errors.generated.go:
--------------------------------------------------------------------------------
1 | package encoding
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/vmess/errors.generated.go:
--------------------------------------------------------------------------------
1 | package vmess
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
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 |
--------------------------------------------------------------------------------
/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 alter_id = 1;
17 | uint32 level = 2;
18 | }
19 |
20 | message Config {
21 | repeated xray.common.protocol.User user = 1;
22 | DefaultConfig default = 2;
23 | DetourConfig detour = 3;
24 | bool secure_encryption_only = 4;
25 | }
26 |
--------------------------------------------------------------------------------
/proxy/vmess/inbound/errors.generated.go:
--------------------------------------------------------------------------------
1 | package inbound
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/proxy/vmess/outbound/config.go:
--------------------------------------------------------------------------------
1 | package outbound
2 |
--------------------------------------------------------------------------------
/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 | repeated xray.common.protocol.ServerEndpoint Receiver = 1;
13 | }
14 |
--------------------------------------------------------------------------------
/proxy/vmess/outbound/errors.generated.go:
--------------------------------------------------------------------------------
1 | package outbound
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
8 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
9 |
--------------------------------------------------------------------------------
/proxy/vmess/vmessCtxInterface.go:
--------------------------------------------------------------------------------
1 | package vmess
2 |
3 | // example
4 | const AlterID = "VMessCtxInterface_AlterID"
5 |
--------------------------------------------------------------------------------
/testing/scenarios/common_coverage.go:
--------------------------------------------------------------------------------
1 | // +build coverage
2 |
3 | package scenarios
4 |
5 | import (
6 | "bytes"
7 | "os"
8 | "os/exec"
9 |
10 | "github.com/xtls/xray-core/common/uuid"
11 | )
12 |
13 | func BuildXray() error {
14 | genTestBinaryPath()
15 | if _, err := os.Stat(testBinaryPath); err == nil {
16 | return nil
17 | }
18 |
19 | cmd := exec.Command("go", "test", "-tags", "coverage coveragemain", "-coverpkg", "github.com/xtls/xray-core/...", "-c", "-o", testBinaryPath, GetSourcePath())
20 | return cmd.Run()
21 | }
22 |
23 | func RunXrayProtobuf(config []byte) *exec.Cmd {
24 | genTestBinaryPath()
25 |
26 | covDir := os.Getenv("XRAY_COV")
27 | os.MkdirAll(covDir, os.ModeDir)
28 | randomID := uuid.New()
29 | profile := randomID.String() + ".out"
30 | proc := exec.Command(testBinaryPath, "-config=stdin:", "-format=pb", "-test.run", "TestRunMainForCoverage", "-test.coverprofile", profile, "-test.outputdir", covDir)
31 | proc.Stdin = bytes.NewBuffer(config)
32 | proc.Stderr = os.Stderr
33 | proc.Stdout = os.Stdout
34 |
35 | return proc
36 | }
37 |
--------------------------------------------------------------------------------
/testing/scenarios/common_regular.go:
--------------------------------------------------------------------------------
1 | // +build !coverage
2 |
3 | package scenarios
4 |
5 | import (
6 | "bytes"
7 | "fmt"
8 | "os"
9 | "os/exec"
10 | )
11 |
12 | func BuildXray() error {
13 | genTestBinaryPath()
14 | if _, err := os.Stat(testBinaryPath); err == nil {
15 | return nil
16 | }
17 |
18 | fmt.Printf("Building Xray into path (%s)\n", testBinaryPath)
19 | cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath())
20 | cmd.Stdout = os.Stdout
21 | cmd.Stderr = os.Stderr
22 | return cmd.Run()
23 | }
24 |
25 | func RunXrayProtobuf(config []byte) *exec.Cmd {
26 | genTestBinaryPath()
27 | proc := exec.Command(testBinaryPath, "-config=stdin:", "-format=pb")
28 | proc.Stdin = bytes.NewBuffer(config)
29 | proc.Stderr = os.Stderr
30 | proc.Stdout = os.Stdout
31 |
32 | return proc
33 | }
34 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/global/config.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import (
4 | "github.com/xtls/xray-core/transport/internet"
5 | )
6 |
7 | // Apply applies this Config.
8 | func (c *Config) Apply() error {
9 | if c == nil {
10 | return nil
11 | }
12 | return internet.ApplyGlobalTransportSettings(c.TransportSettings)
13 | }
14 |
--------------------------------------------------------------------------------
/transport/global/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.transport;
4 | option csharp_namespace = "Xray.Transport.Global";
5 | option go_package = "github.com/xtls/xray-core/transport/global";
6 | option java_package = "com.xray.transport.global";
7 | option java_multiple_files = true;
8 |
9 | import "transport/internet/config.proto";
10 |
11 | // Global transport settings. This affects all type of connections that go
12 | // through Xray. Deprecated. Use each settings in StreamConfig.
13 | message Config {
14 | option deprecated = true;
15 | repeated xray.transport.internet.TransportConfig transport_settings = 1;
16 | }
17 |
--------------------------------------------------------------------------------
/transport/internet/connection.go:
--------------------------------------------------------------------------------
1 | package internet
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 StatCouterConnection struct {
14 | Connection
15 | ReadCounter stats.Counter
16 | WriteCounter stats.Counter
17 | }
18 |
19 | func (c *StatCouterConnection) 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 *StatCouterConnection) 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 |
--------------------------------------------------------------------------------
/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 |
9 | "github.com/xtls/xray-core/common"
10 | "github.com/xtls/xray-core/common/net"
11 | "github.com/xtls/xray-core/testing/servers/tcp"
12 | . "github.com/xtls/xray-core/transport/internet"
13 | )
14 |
15 | func TestDialWithLocalAddr(t *testing.T) {
16 | server := &tcp.Server{}
17 | dest, err := server.Start()
18 | common.Must(err)
19 | defer server.Close()
20 |
21 | conn, err := DialSystem(context.Background(), net.TCPDestination(net.LocalHostIP, dest.Port), nil)
22 | common.Must(err)
23 | if r := cmp.Diff(conn.RemoteAddr().String(), "127.0.0.1:"+dest.Port.String()); r != "" {
24 | t.Error(r)
25 | }
26 | conn.Close()
27 | }
28 |
--------------------------------------------------------------------------------
/transport/internet/domainsocket/config.go:
--------------------------------------------------------------------------------
1 | package domainsocket
2 |
3 | import (
4 | "github.com/xtls/xray-core/common"
5 | "github.com/xtls/xray-core/common/net"
6 | "github.com/xtls/xray-core/transport/internet"
7 | )
8 |
9 | const protocolName = "domainsocket"
10 | const sizeofSunPath = 108
11 |
12 | func (c *Config) GetUnixAddr() (*net.UnixAddr, error) {
13 | path := c.Path
14 | if path == "" {
15 | return nil, newError("empty domain socket path")
16 | }
17 | if c.Abstract && path[0] != '@' {
18 | path = "@" + path
19 | }
20 | if c.Abstract && c.Padding {
21 | raw := []byte(path)
22 | addr := make([]byte, sizeofSunPath)
23 | copy(addr, raw)
24 | path = string(addr)
25 | }
26 | return &net.UnixAddr{
27 | Name: path,
28 | Net: "unix",
29 | }, nil
30 | }
31 |
32 | func init() {
33 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
34 | return new(Config)
35 | }))
36 | }
37 |
--------------------------------------------------------------------------------
/transport/internet/domainsocket/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.transport.internet.domainsocket;
4 | option csharp_namespace = "Xray.Transport.Internet.DomainSocket";
5 | option go_package = "github.com/xtls/xray-core/transport/internet/domainsocket";
6 | option java_package = "com.xray.transport.internet.domainsocket";
7 | option java_multiple_files = true;
8 |
9 | message Config {
10 | // Path of the domain socket. This overrides the IP/Port parameter from
11 | // upstream caller.
12 | string path = 1;
13 | // Abstract speicifies whether to use abstract namespace or not.
14 | // Traditionally Unix domain socket is file system based. Abstract domain
15 | // socket can be used without acquiring file lock.
16 | bool abstract = 2;
17 | // Some apps, eg. haproxy, use the full length of sockaddr_un.sun_path to
18 | // connect(2) or bind(2) when using abstract UDS.
19 | bool padding = 3;
20 | }
21 |
--------------------------------------------------------------------------------
/transport/internet/domainsocket/errgen.go:
--------------------------------------------------------------------------------
1 | package domainsocket
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/transport/internet/domainsocket/errors.generated.go:
--------------------------------------------------------------------------------
1 | package domainsocket
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/errors.generated.go:
--------------------------------------------------------------------------------
1 | package internet
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/filelocker_other.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package internet
4 |
5 | import (
6 | "os"
7 |
8 | "golang.org/x/sys/unix"
9 | )
10 |
11 | // Acquire lock
12 | func (fl *FileLocker) Acquire() error {
13 | f, err := os.Create(fl.path)
14 | if err != nil {
15 | return err
16 | }
17 | if err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil {
18 | f.Close()
19 | return newError("failed to lock file: ", fl.path).Base(err)
20 | }
21 | fl.file = f
22 | return nil
23 | }
24 |
25 | // Release lock
26 | func (fl *FileLocker) Release() {
27 | if err := unix.Flock(int(fl.file.Fd()), unix.LOCK_UN); err != nil {
28 | newError("failed to unlock file: ", fl.path).Base(err).WriteToLog()
29 | }
30 | if err := fl.file.Close(); err != nil {
31 | newError("failed to close file: ", fl.path).Base(err).WriteToLog()
32 | }
33 | if err := os.Remove(fl.path); err != nil {
34 | newError("failed to remove file: ", fl.path).Base(err).WriteToLog()
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/grpc/config.go:
--------------------------------------------------------------------------------
1 | package grpc
2 |
3 | import (
4 | "github.com/xtls/xray-core/common"
5 | "github.com/xtls/xray-core/transport/internet"
6 | )
7 |
8 | const protocolName = "grpc"
9 |
10 | func init() {
11 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
12 | return new(Config)
13 | }))
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 host = 1;
8 | string service_name = 2;
9 | bool multi_mode = 3;
10 | }
11 |
--------------------------------------------------------------------------------
/transport/internet/grpc/encoding/encoding.go:
--------------------------------------------------------------------------------
1 | package encoding
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/transport/internet/grpc/encoding/errors.generated.go:
--------------------------------------------------------------------------------
1 | package encoding
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/grpc/errors.generated.go:
--------------------------------------------------------------------------------
1 | package grpc
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/grpc/grpc.go:
--------------------------------------------------------------------------------
1 | package grpc
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/transport/internet/header.go:
--------------------------------------------------------------------------------
1 | package internet
2 |
3 | import (
4 | "context"
5 | "net"
6 |
7 | "github.com/xtls/xray-core/common"
8 | )
9 |
10 | type PacketHeader interface {
11 | Size() int32
12 | Serialize([]byte)
13 | }
14 |
15 | func CreatePacketHeader(config interface{}) (PacketHeader, error) {
16 | header, err := common.CreateObject(context.Background(), config)
17 | if err != nil {
18 | return nil, err
19 | }
20 | if h, ok := header.(PacketHeader); ok {
21 | return h, nil
22 | }
23 | return nil, newError("not a packet header")
24 | }
25 |
26 | type ConnectionAuthenticator interface {
27 | Client(net.Conn) net.Conn
28 | Server(net.Conn) net.Conn
29 | }
30 |
31 | func CreateConnectionAuthenticator(config interface{}) (ConnectionAuthenticator, error) {
32 | auth, err := common.CreateObject(context.Background(), config)
33 | if err != nil {
34 | return nil, err
35 | }
36 | if a, ok := auth.(ConnectionAuthenticator); ok {
37 | return a, nil
38 | }
39 | return nil, newError("not a ConnectionAuthenticator")
40 | }
41 |
--------------------------------------------------------------------------------
/transport/internet/headers/http/errors.generated.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/headers/http/linkedreadRequest.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "bufio"
5 | "net/http"
6 |
7 | _ "unsafe" // required to use //go:linkname
8 | )
9 |
10 | //go:linkname readRequest net/http.readRequest
11 | func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *http.Request, err error)
12 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/http/config.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "github.com/xtls/xray-core/common"
5 | "github.com/xtls/xray-core/common/dice"
6 | "github.com/xtls/xray-core/transport/internet"
7 | )
8 |
9 | const protocolName = "http"
10 |
11 | func (c *Config) getHosts() []string {
12 | if len(c.Host) == 0 {
13 | return []string{"www.example.com"}
14 | }
15 | return c.Host
16 | }
17 |
18 | func (c *Config) isValidHost(host string) bool {
19 | hosts := c.getHosts()
20 | for _, h := range hosts {
21 | if h == host {
22 | return true
23 | }
24 | }
25 | return false
26 | }
27 |
28 | func (c *Config) getRandomHost() string {
29 | hosts := c.getHosts()
30 | return hosts[dice.Roll(len(hosts))]
31 | }
32 |
33 | func (c *Config) getNormalizedPath() string {
34 | if c.Path == "" {
35 | return "/"
36 | }
37 | if c.Path[0] != '/' {
38 | return "/" + c.Path
39 | }
40 | return c.Path
41 | }
42 |
43 | func init() {
44 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
45 | return new(Config)
46 | }))
47 | }
48 |
--------------------------------------------------------------------------------
/transport/internet/http/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.transport.internet.http;
4 | option csharp_namespace = "Xray.Transport.Internet.Http";
5 | option go_package = "github.com/xtls/xray-core/transport/internet/http";
6 | option java_package = "com.xray.transport.internet.http";
7 | option java_multiple_files = true;
8 |
9 | message Config {
10 | repeated string host = 1;
11 | string path = 2;
12 | }
13 |
--------------------------------------------------------------------------------
/transport/internet/http/errors.generated.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/http/http.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/transport/internet/internet.go:
--------------------------------------------------------------------------------
1 | package internet
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/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/crypt_test.go:
--------------------------------------------------------------------------------
1 | package kcp_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/google/go-cmp/cmp"
7 |
8 | "github.com/xtls/xray-core/common"
9 | . "github.com/xtls/xray-core/transport/internet/kcp"
10 | )
11 |
12 | func TestSimpleAuthenticator(t *testing.T) {
13 | cache := make([]byte, 512)
14 |
15 | payload := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
16 |
17 | auth := NewSimpleAuthenticator()
18 | b := auth.Seal(cache[:0], nil, payload, nil)
19 | c, err := auth.Open(cache[:0], nil, b, nil)
20 | common.Must(err)
21 | if r := cmp.Diff(c, payload); r != "" {
22 | t.Error(r)
23 | }
24 | }
25 |
26 | func TestSimpleAuthenticator2(t *testing.T) {
27 | cache := make([]byte, 512)
28 |
29 | payload := []byte{'a', 'b'}
30 |
31 | auth := NewSimpleAuthenticator()
32 | b := auth.Seal(cache[:0], nil, payload, nil)
33 | c, err := auth.Open(cache[:0], nil, b, nil)
34 | common.Must(err)
35 | if r := cmp.Diff(c, payload); r != "" {
36 | t.Error(r)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/transport/internet/kcp/cryptreal.go:
--------------------------------------------------------------------------------
1 | package kcp
2 |
3 | import (
4 | "crypto/aes"
5 | "crypto/cipher"
6 | "crypto/sha256"
7 |
8 | "github.com/xtls/xray-core/common"
9 | )
10 |
11 | func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD {
12 | hashedSeed := sha256.Sum256([]byte(seed))
13 | aesBlock := common.Must2(aes.NewCipher(hashedSeed[:16])).(cipher.Block)
14 | return common.Must2(cipher.NewGCM(aesBlock)).(cipher.AEAD)
15 | }
16 |
--------------------------------------------------------------------------------
/transport/internet/kcp/errors.generated.go:
--------------------------------------------------------------------------------
1 | package kcp
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/kcp/kcp.go:
--------------------------------------------------------------------------------
1 | // Package kcp - A Fast and Reliable ARQ Protocol
2 | //
3 | // Acknowledgement:
4 | // skywind3000@github for inventing the KCP protocol
5 | // xtaci@github for translating to Golang
6 | package kcp
7 |
8 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
9 |
--------------------------------------------------------------------------------
/transport/internet/kcp/xor.go:
--------------------------------------------------------------------------------
1 | // +build !amd64
2 |
3 | package kcp
4 |
5 | // xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len
6 | func xorfwd(x []byte) {
7 | for i := 4; i < len(x); i++ {
8 | x[i] ^= x[i-4]
9 | }
10 | }
11 |
12 | // xorbkd performs XOR backwords in words, x[i] ^= x[i-4], i from len to 0
13 | func xorbkd(x []byte) {
14 | for i := len(x) - 1; i >= 4; i-- {
15 | x[i] ^= x[i-4]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/memory_settings.go:
--------------------------------------------------------------------------------
1 | package internet
2 |
3 | // MemoryStreamConfig is a parsed form of StreamConfig. This is used to reduce number of Protobuf parsing.
4 | type MemoryStreamConfig struct {
5 | ProtocolName string
6 | ProtocolSettings interface{}
7 | SecurityType string
8 | SecuritySettings interface{}
9 | SocketSettings *SocketConfig
10 | }
11 |
12 | // ToMemoryStreamConfig converts a StreamConfig to MemoryStreamConfig. It returns a default non-nil MemoryStreamConfig for nil input.
13 | func ToMemoryStreamConfig(s *StreamConfig) (*MemoryStreamConfig, error) {
14 | ets, err := s.GetEffectiveTransportSettings()
15 | if err != nil {
16 | return nil, err
17 | }
18 |
19 | mss := &MemoryStreamConfig{
20 | ProtocolName: s.GetEffectiveProtocol(),
21 | ProtocolSettings: ets,
22 | }
23 |
24 | if s != nil {
25 | mss.SocketSettings = s.SocketSettings
26 | }
27 |
28 | if s != nil && s.HasSecuritySettings() {
29 | ess, err := s.GetEffectiveSecuritySettings()
30 | if err != nil {
31 | return nil, err
32 | }
33 | mss.SecurityType = s.SecurityType
34 | mss.SecuritySettings = ess
35 | }
36 |
37 | return mss, nil
38 | }
39 |
--------------------------------------------------------------------------------
/transport/internet/quic/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.transport.internet.quic;
4 | option csharp_namespace = "Xray.Transport.Internet.Quic";
5 | option go_package = "github.com/xtls/xray-core/transport/internet/quic";
6 | option java_package = "com.xray.transport.internet.quic";
7 | option java_multiple_files = true;
8 |
9 | import "common/serial/typed_message.proto";
10 | import "common/protocol/headers.proto";
11 |
12 | message Config {
13 | string key = 1;
14 | xray.common.protocol.SecurityConfig security = 2;
15 | xray.common.serial.TypedMessage header = 3;
16 | }
17 |
--------------------------------------------------------------------------------
/transport/internet/quic/errors.generated.go:
--------------------------------------------------------------------------------
1 | package quic
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/quic/pool.go:
--------------------------------------------------------------------------------
1 | package quic
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/xtls/xray-core/common/bytespool"
7 | )
8 |
9 | var pool *sync.Pool
10 |
11 | func init() {
12 | pool = bytespool.GetPool(2048)
13 | }
14 |
15 | func getBuffer() []byte {
16 | return pool.Get().([]byte)
17 | }
18 |
19 | func putBuffer(p []byte) {
20 | pool.Put(p)
21 | }
22 |
--------------------------------------------------------------------------------
/transport/internet/quic/quic.go:
--------------------------------------------------------------------------------
1 | package quic
2 |
3 | import (
4 | "github.com/xtls/xray-core/common"
5 | "github.com/xtls/xray-core/transport/internet"
6 | )
7 |
8 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
9 |
10 | // Here is some modification needs to be done before update quic vendor.
11 | // * use bytespool in buffer_pool.go
12 | // * set MaxReceivePacketSize to 1452 - 32 (16 bytes auth, 16 bytes head)
13 | //
14 | //
15 |
16 | const protocolName = "quic"
17 | const internalDomain = "quic.internal.example.com"
18 |
19 | func init() {
20 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
21 | return new(Config)
22 | }))
23 | }
24 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/sockopt_other.go:
--------------------------------------------------------------------------------
1 | // +build js dragonfly netbsd openbsd solaris
2 |
3 | package internet
4 |
5 | func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
6 | return nil
7 | }
8 |
9 | func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
10 | return nil
11 | }
12 |
13 | func bindAddr(fd uintptr, ip []byte, port uint32) error {
14 | return nil
15 | }
16 |
17 | func setReuseAddr(fd uintptr) error {
18 | return nil
19 | }
20 |
21 | func setReusePort(fd uintptr) error {
22 | return nil
23 | }
24 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/system_dialer_context.go:
--------------------------------------------------------------------------------
1 | package internet
2 |
3 | import "context"
4 |
5 | type systemDialer int
6 |
7 | const systemDialerKey systemDialer = 0
8 |
9 | func ContextWithLookupDomain(ctx context.Context, domain string) context.Context {
10 | return context.WithValue(ctx, systemDialerKey, domain)
11 | }
12 |
13 | func LookupDomainFromContext(ctx context.Context) string {
14 | if domain, ok := ctx.Value(systemDialerKey).(string); ok {
15 | return domain
16 | }
17 | return ""
18 | }
19 |
--------------------------------------------------------------------------------
/transport/internet/system_listener_test.go:
--------------------------------------------------------------------------------
1 | package internet_test
2 |
3 | import (
4 | "context"
5 | "net"
6 | "testing"
7 |
8 | "github.com/xtls/xray-core/common"
9 | "github.com/xtls/xray-core/transport/internet"
10 | )
11 |
12 | func TestRegisterListenerController(t *testing.T) {
13 | var gotFd uintptr
14 |
15 | common.Must(internet.RegisterListenerController(func(network string, addr string, fd uintptr) error {
16 | gotFd = fd
17 | return nil
18 | }))
19 |
20 | conn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
21 | IP: net.IPv4zero,
22 | }, nil)
23 | common.Must(err)
24 | common.Must(conn.Close())
25 |
26 | if gotFd == 0 {
27 | t.Error("expected none-zero fd, but actually 0")
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/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 | const protocolName = "tcp"
9 |
10 | func init() {
11 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
12 | return new(Config)
13 | }))
14 | }
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/transport/internet/tcp/errors.generated.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/tcp/sockopt_freebsd.go:
--------------------------------------------------------------------------------
1 | // +build freebsd
2 |
3 | package tcp
4 |
5 | import (
6 | "github.com/xtls/xray-core/common/net"
7 | "github.com/xtls/xray-core/transport/internet"
8 | )
9 |
10 | // GetOriginalDestination from tcp conn
11 | func GetOriginalDestination(conn internet.Connection) (net.Destination, error) {
12 | la := conn.LocalAddr()
13 | ra := conn.RemoteAddr()
14 | ip, port, err := internet.OriginalDst(la, ra)
15 | if err != nil {
16 | return net.Destination{}, newError("failed to get destination").Base(err)
17 | }
18 | dest := net.TCPDestination(net.IPAddress(ip), net.Port(port))
19 | if !dest.IsValid() {
20 | return net.Destination{}, newError("failed to parse destination.")
21 | }
22 | return dest, nil
23 | }
24 |
--------------------------------------------------------------------------------
/transport/internet/tcp/sockopt_linux_test.go:
--------------------------------------------------------------------------------
1 | // +build linux
2 |
3 | package tcp_test
4 |
5 | import (
6 | "context"
7 | "strings"
8 | "testing"
9 |
10 | "github.com/xtls/xray-core/common"
11 | "github.com/xtls/xray-core/testing/servers/tcp"
12 | "github.com/xtls/xray-core/transport/internet"
13 | . "github.com/xtls/xray-core/transport/internet/tcp"
14 | )
15 |
16 | func TestGetOriginalDestination(t *testing.T) {
17 | tcpServer := tcp.Server{}
18 | dest, err := tcpServer.Start()
19 | common.Must(err)
20 | defer tcpServer.Close()
21 |
22 | config, err := internet.ToMemoryStreamConfig(nil)
23 | common.Must(err)
24 | conn, err := Dial(context.Background(), dest, config)
25 | common.Must(err)
26 | defer conn.Close()
27 |
28 | originalDest, err := GetOriginalDestination(conn)
29 | if !(dest == originalDest || strings.Contains(err.Error(), "failed to call getsockopt")) {
30 | t.Error("unexpected state")
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/transport/internet/tcp/sockopt_other.go:
--------------------------------------------------------------------------------
1 | // +build !linux,!freebsd
2 |
3 | package tcp
4 |
5 | import (
6 | "github.com/xtls/xray-core/common/net"
7 | "github.com/xtls/xray-core/transport/internet"
8 | )
9 |
10 | func GetOriginalDestination(conn internet.Connection) (net.Destination, error) {
11 | return net.Destination{}, nil
12 | }
13 |
--------------------------------------------------------------------------------
/transport/internet/tcp/tcp.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
--------------------------------------------------------------------------------
/transport/internet/tls/config_other.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package tls
4 |
5 | import (
6 | "crypto/x509"
7 | "sync"
8 | )
9 |
10 | type rootCertsCache struct {
11 | sync.Mutex
12 | pool *x509.CertPool
13 | }
14 |
15 | func (c *rootCertsCache) load() (*x509.CertPool, error) {
16 | c.Lock()
17 | defer c.Unlock()
18 |
19 | if c.pool != nil {
20 | return c.pool, nil
21 | }
22 |
23 | pool, err := x509.SystemCertPool()
24 | if err != nil {
25 | return nil, err
26 | }
27 | c.pool = pool
28 | return pool, nil
29 | }
30 |
31 | var rootCerts rootCertsCache
32 |
33 | func (c *Config) getCertPool() (*x509.CertPool, error) {
34 | if c.DisableSystemRoot {
35 | return c.loadSelfCertPool()
36 | }
37 |
38 | if len(c.Certificate) == 0 {
39 | return rootCerts.load()
40 | }
41 |
42 | pool, err := x509.SystemCertPool()
43 | if err != nil {
44 | return nil, newError("system root").AtWarning().Base(err)
45 | }
46 | for _, cert := range c.Certificate {
47 | if !pool.AppendCertsFromPEM(cert.Certificate) {
48 | return nil, newError("append cert to root").AtWarning().Base(err)
49 | }
50 | }
51 | return pool, err
52 | }
53 |
--------------------------------------------------------------------------------
/transport/internet/tls/config_windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package tls
4 |
5 | import "crypto/x509"
6 |
7 | func (c *Config) getCertPool() (*x509.CertPool, error) {
8 | if c.DisableSystemRoot {
9 | return c.loadSelfCertPool()
10 | }
11 |
12 | return nil, nil
13 | }
14 |
--------------------------------------------------------------------------------
/transport/internet/tls/errors.generated.go:
--------------------------------------------------------------------------------
1 | package tls
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package xray.transport.internet.tunnel;
4 | option csharp_namespace = "Xray.Transport.Internet.Tunnel";
5 | option go_package = "github.com/xtls/xray-core/transport/internet/tunnel";
6 | option java_package = "com.xray.transport.internet.tunnel";
7 | option java_multiple_files = true;
8 |
9 | message Config {
10 | string name = 1;
11 | string address = 2;
12 | string gateway = 3;
13 | string mask = 4;
14 | repeated string dns = 5;
15 | bool fix_dns_leak = 6;
16 | }
17 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/errors.generated.go:
--------------------------------------------------------------------------------
1 | package tunnel
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/handler.go:
--------------------------------------------------------------------------------
1 | // +build !confonly
2 |
3 | package tunnel
4 |
5 | import (
6 | "net"
7 |
8 | xstack "github.com/xtls/xray-core/transport/internet/tunnel/stack"
9 | )
10 |
11 | func (l *listener) HandleStream(conn net.Conn) error {
12 | target := conn.RemoteAddr().(*net.TCPAddr)
13 | newError("handle tcp connect to tcp:", target.String()).AtDebug().WriteToLog()
14 | l.acceptConn(conn)
15 | return nil
16 | }
17 |
18 | func (l *listener) HandlePacket(pconn xstack.PacketConn, target *net.UDPAddr) error {
19 | newError("handle udp:", target.String()).AtDebug().WriteToLog()
20 | p := makeUDP(pconn)
21 | l.acceptConn(p)
22 | return nil
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/readme.md:
--------------------------------------------------------------------------------
1 | Reference:
2 | - https://github.com/xjasonlyu/tun2socks
3 | - https://github.com/imgk/shadow
--------------------------------------------------------------------------------
/transport/internet/tunnel/stack/errors.generated.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/stack/tcp.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | import (
4 | "gvisor.dev/gvisor/pkg/tcpip"
5 | "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
6 | "gvisor.dev/gvisor/pkg/waiter"
7 | "net"
8 | )
9 |
10 | type TCPConn struct {
11 | *gonet.TCPConn
12 | }
13 |
14 | func (t *TCPConn) LocalAddr() net.Addr { return t.TCPConn.RemoteAddr() }
15 | func (t *TCPConn) RemoteAddr() net.Addr { return t.TCPConn.LocalAddr() }
16 |
17 | func getTCPConn(wq *waiter.Queue, ep tcpip.Endpoint) *TCPConn {
18 | return &TCPConn{
19 | gonet.NewTCPConn(wq, ep),
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/stack/unsafe.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | import (
4 | "gvisor.dev/gvisor/pkg/tcpip"
5 | "gvisor.dev/gvisor/pkg/tcpip/buffer"
6 | "gvisor.dev/gvisor/pkg/tcpip/header"
7 | "gvisor.dev/gvisor/pkg/tcpip/stack"
8 | "unsafe"
9 | )
10 |
11 | var _ unsafe.Pointer = unsafe.Pointer(nil)
12 |
13 | // verifyChecksum verifies the checksum unless RX checksum offload is enabled.
14 | // On IPv4, UDP checksum is optional, and a zero value means the transmitter
15 | // omitted the checksum generation (RFC768).
16 | // On IPv6, UDP checksum is not optional (RFC2460 Section 8.1).
17 | //
18 | //go:linkname verifyChecksum gvisor.dev/gvisor/pkg/tcpip/transport/udp.verifyChecksum
19 | func verifyChecksum(hdr header.UDP, pkt *stack.PacketBuffer) bool
20 |
21 | // sendUDP sends a UDP segment via the provided network endpoint and under the
22 | // provided identity.
23 | //
24 | //go:linkname sendUDP gvisor.dev/gvisor/pkg/tcpip/transport/udp.sendUDP
25 | func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort uint16, ttl uint8, useDefaultTTL bool, tos uint8, owner tcpip.PacketOwner, noChecksum bool) *tcpip.Error
26 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/tun.go:
--------------------------------------------------------------------------------
1 | // +build !confonly
2 |
3 | package tunnel
4 |
5 | import (
6 | "net"
7 |
8 | "github.com/xtls/xray-core/common"
9 | "github.com/xtls/xray-core/transport/internet"
10 | _ "github.com/xtls/xray-core/transport/internet/tunnel/stack"
11 | )
12 |
13 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
14 |
15 | const protocolName = "tunnel"
16 |
17 | type WriteFrom func([]byte, net.Addr) (int, error)
18 |
19 | func init() {
20 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
21 | return new(Config)
22 | }))
23 | }
24 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/tun/errors.generated.go:
--------------------------------------------------------------------------------
1 | package tun
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/tunnel/tun/tun.go:
--------------------------------------------------------------------------------
1 | package tun
2 |
3 | import (
4 | "io"
5 | )
6 |
7 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
8 |
9 | type Device interface {
10 | io.ReadWriteCloser
11 | GetIdentifier() interface{}
12 | }
13 |
14 | func OpenTUNDevice(name, addr, gw, mask string, dns []string) (Device, error) {
15 | return openTunDev(name, addr, gw, mask, dns)
16 | }
17 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 | )
10 |
11 | func init() {
12 | common.Must(internet.RegisterTransportDialer(protocolName,
13 | func(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
14 | var sockopt *internet.SocketConfig
15 | if streamSettings != nil {
16 | sockopt = streamSettings.SocketSettings
17 | }
18 | conn, err := internet.DialSystem(ctx, dest, sockopt)
19 | if err != nil {
20 | return nil, err
21 | }
22 | // TODO: handle dialer options
23 | return internet.Connection(conn), nil
24 | }))
25 | }
26 |
--------------------------------------------------------------------------------
/transport/internet/udp/errors.generated.go:
--------------------------------------------------------------------------------
1 | package udp
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/udp/hub_freebsd.go:
--------------------------------------------------------------------------------
1 | // +build freebsd
2 |
3 | package udp
4 |
5 | import (
6 | "bytes"
7 | "encoding/gob"
8 | "io"
9 |
10 | "github.com/xtls/xray-core/common/net"
11 | "github.com/xtls/xray-core/transport/internet"
12 | )
13 |
14 | // RetrieveOriginalDest from stored laddr, caddr
15 | func RetrieveOriginalDest(oob []byte) net.Destination {
16 | dec := gob.NewDecoder(bytes.NewBuffer(oob))
17 | var la, ra net.UDPAddr
18 | dec.Decode(&la)
19 | dec.Decode(&ra)
20 | ip, port, err := internet.OriginalDst(&la, &ra)
21 | if err != nil {
22 | return net.Destination{}
23 | }
24 | return net.UDPDestination(net.IPAddress(ip), net.Port(port))
25 | }
26 |
27 | // ReadUDPMsg stores laddr, caddr for later use
28 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {
29 | nBytes, addr, err := conn.ReadFromUDP(payload)
30 | var buf bytes.Buffer
31 | enc := gob.NewEncoder(&buf)
32 | enc.Encode(conn.LocalAddr().(*net.UDPAddr))
33 | enc.Encode(addr)
34 | var reader io.Reader = &buf
35 | noob, _ := reader.Read(oob)
36 | return nBytes, noob, 0, addr, err
37 | }
38 |
--------------------------------------------------------------------------------
/transport/internet/udp/hub_linux.go:
--------------------------------------------------------------------------------
1 | // +build linux
2 |
3 | package udp
4 |
5 | import (
6 | "syscall"
7 |
8 | "github.com/xtls/xray-core/common/net"
9 | "golang.org/x/sys/unix"
10 | )
11 |
12 | func RetrieveOriginalDest(oob []byte) net.Destination {
13 | msgs, err := syscall.ParseSocketControlMessage(oob)
14 | if err != nil {
15 | return net.Destination{}
16 | }
17 | for _, msg := range msgs {
18 | if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {
19 | ip := net.IPAddress(msg.Data[4:8])
20 | port := net.PortFromBytes(msg.Data[2:4])
21 | return net.UDPDestination(ip, port)
22 | } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == unix.IPV6_RECVORIGDSTADDR {
23 | ip := net.IPAddress(msg.Data[8:24])
24 | port := net.PortFromBytes(msg.Data[2:4])
25 | return net.UDPDestination(ip, port)
26 | }
27 | }
28 | return net.Destination{}
29 | }
30 |
31 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {
32 | return conn.ReadMsgUDP(payload, oob)
33 | }
34 |
--------------------------------------------------------------------------------
/transport/internet/udp/hub_other.go:
--------------------------------------------------------------------------------
1 | // +build !linux,!freebsd
2 |
3 | package udp
4 |
5 | import (
6 | "github.com/xtls/xray-core/common/net"
7 | )
8 |
9 | func RetrieveOriginalDest(oob []byte) net.Destination {
10 | return net.Destination{}
11 | }
12 |
13 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {
14 | nBytes, addr, err := conn.ReadFromUDP(payload)
15 | return nBytes, 0, 0, addr, err
16 | }
17 |
--------------------------------------------------------------------------------
/transport/internet/udp/udp.go:
--------------------------------------------------------------------------------
1 | package udp
2 |
3 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
4 |
5 | const protocolName = "udp"
6 |
--------------------------------------------------------------------------------
/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 | const protocolName = "websocket"
11 |
12 | func (c *Config) GetNormalizedPath() string {
13 | path := c.Path
14 | if path == "" {
15 | return "/"
16 | }
17 | if path[0] != '/' {
18 | return "/" + path
19 | }
20 | return path
21 | }
22 |
23 | func (c *Config) GetRequestHeader() http.Header {
24 | header := http.Header{}
25 | for _, h := range c.Header {
26 | header.Add(h.Key, h.Value)
27 | }
28 | return header
29 | }
30 |
31 | func init() {
32 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
33 | return new(Config)
34 | }))
35 | }
36 |
--------------------------------------------------------------------------------
/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 Header {
10 | string key = 1;
11 | string value = 2;
12 | }
13 |
14 | message Config {
15 | reserved 1;
16 |
17 | // URL path to the WebSocket service. Empty value means root(/).
18 | string path = 2;
19 |
20 | repeated Header header = 3;
21 |
22 | bool accept_proxy_protocol = 4;
23 |
24 | uint32 ed = 5;
25 | }
26 |
--------------------------------------------------------------------------------
/transport/internet/websocket/errors.generated.go:
--------------------------------------------------------------------------------
1 | package websocket
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/websocket/ws.go:
--------------------------------------------------------------------------------
1 | /*Package websocket implements WebSocket transport
2 |
3 | WebSocket transport implements an HTTP(S) compliable, surveillance proof transport method with plausible deniability.
4 | */
5 | package websocket
6 |
7 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
8 |
--------------------------------------------------------------------------------
/transport/internet/xtls/config_other.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package xtls
4 |
5 | import (
6 | "crypto/x509"
7 | "sync"
8 | )
9 |
10 | type rootCertsCache struct {
11 | sync.Mutex
12 | pool *x509.CertPool
13 | }
14 |
15 | func (c *rootCertsCache) load() (*x509.CertPool, error) {
16 | c.Lock()
17 | defer c.Unlock()
18 |
19 | if c.pool != nil {
20 | return c.pool, nil
21 | }
22 |
23 | pool, err := x509.SystemCertPool()
24 | if err != nil {
25 | return nil, err
26 | }
27 | c.pool = pool
28 | return pool, nil
29 | }
30 |
31 | var rootCerts rootCertsCache
32 |
33 | func (c *Config) getCertPool() (*x509.CertPool, error) {
34 | if c.DisableSystemRoot {
35 | return c.loadSelfCertPool()
36 | }
37 |
38 | if len(c.Certificate) == 0 {
39 | return rootCerts.load()
40 | }
41 |
42 | pool, err := x509.SystemCertPool()
43 | if err != nil {
44 | return nil, newError("system root").AtWarning().Base(err)
45 | }
46 | for _, cert := range c.Certificate {
47 | if !pool.AppendCertsFromPEM(cert.Certificate) {
48 | return nil, newError("append cert to root").AtWarning().Base(err)
49 | }
50 | }
51 | return pool, err
52 | }
53 |
--------------------------------------------------------------------------------
/transport/internet/xtls/config_windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package xtls
4 |
5 | import "crypto/x509"
6 |
7 | func (c *Config) getCertPool() (*x509.CertPool, error) {
8 | if c.DisableSystemRoot {
9 | return c.loadSelfCertPool()
10 | }
11 |
12 | return nil, nil
13 | }
14 |
--------------------------------------------------------------------------------
/transport/internet/xtls/errors.generated.go:
--------------------------------------------------------------------------------
1 | package xtls
2 |
3 | import "github.com/xtls/xray-core/common/errors"
4 |
5 | type errPathObjHolder struct{}
6 |
7 | func newError(values ...interface{}) *errors.Error {
8 | return errors.New(values...).WithPathObj(errPathObjHolder{})
9 | }
10 |
--------------------------------------------------------------------------------
/transport/internet/xtls/xtls.go:
--------------------------------------------------------------------------------
1 | package xtls
2 |
3 | import (
4 | xtls "github.com/xtls/go"
5 |
6 | "github.com/xtls/xray-core/common/net"
7 | )
8 |
9 | //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
10 |
11 | type Conn struct {
12 | *xtls.Conn
13 | }
14 |
15 | func (c *Conn) HandshakeAddress() net.Address {
16 | if err := c.Handshake(); err != nil {
17 | return nil
18 | }
19 | state := c.ConnectionState()
20 | if state.ServerName == "" {
21 | return nil
22 | }
23 | return net.ParseAddress(state.ServerName)
24 | }
25 |
26 | // Client initiates a XTLS client handshake on the given connection.
27 | func Client(c net.Conn, config *xtls.Config) net.Conn {
28 | xtlsConn := xtls.Client(c, config)
29 | return &Conn{Conn: xtlsConn}
30 | }
31 |
32 | // Server initiates a XTLS server handshake on the given connection.
33 | func Server(c net.Conn, config *xtls.Config) net.Conn {
34 | xtlsConn := xtls.Server(c, config)
35 | return &Conn{Conn: xtlsConn}
36 | }
37 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | // Interrupt implements common.Interruptible.
23 | func (w *Writer) Interrupt() {
24 | w.pipe.Interrupt()
25 | }
26 |
--------------------------------------------------------------------------------