├── .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 | --------------------------------------------------------------------------------