├── .github ├── dependabot.yml ├── linters │ └── .golangci.yml └── workflows │ ├── codeql-analysis.yml │ ├── linter.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── annotations.go ├── app ├── app.go ├── browserforwarder │ ├── config.pb.go │ ├── config.proto │ ├── errors.generated.go │ └── forwarder.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.go │ ├── config.pb.go │ ├── config.proto │ ├── dns.go │ ├── dns_test.go │ ├── dnscommon.go │ ├── dnscommon_test.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_doh.go │ ├── nameserver_doh_test.go │ ├── nameserver_fakedns.go │ ├── nameserver_local.go │ ├── nameserver_local_test.go │ ├── nameserver_quic.go │ ├── nameserver_quic_test.go │ ├── nameserver_tcp.go │ ├── nameserver_tcp_test.go │ └── nameserver_udp.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 ├── observatory │ ├── command │ │ ├── command.go │ │ ├── command.pb.go │ │ ├── command.proto │ │ └── command_grpc.pb.go │ ├── config.pb.go │ ├── config.proto │ ├── errors.generated.go │ ├── explainErrors.go │ ├── observatory.go │ └── observer.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 │ └── strategy_leastping.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 │ ├── antireplay.go │ ├── bloomring.go │ └── replayfilter.go ├── bitmask │ ├── byte.go │ └── byte_test.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 ├── drain │ ├── drain.go │ ├── drainer.go │ └── errors.generated.go ├── errors.generated.go ├── errors │ ├── errorgen │ │ └── main.go │ ├── errors.go │ ├── errors_test.go │ └── multi_error.go ├── interfaces.go ├── log │ ├── access.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 │ ├── 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 ├── 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 ├── 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 ├── config.go ├── config.pb.go ├── config.proto ├── context.go ├── context_test.go ├── core.go ├── errors.generated.go ├── features ├── dns │ ├── client.go │ ├── fakedns.go │ └── localdns │ │ ├── client.go │ │ └── errors.generated.go ├── errors.generated.go ├── extension │ ├── browser.go │ ├── contextreceiver.go │ └── observatory.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 ├── format.go ├── functions.go ├── functions_test.go ├── go.mod ├── go.sum ├── infra ├── conf │ ├── api.go │ ├── blackhole.go │ ├── blackhole_test.go │ ├── browser_forwarder.go │ ├── buildable.go │ ├── cfgcommon │ │ ├── common.go │ │ ├── common_test.go │ │ ├── duration │ │ │ ├── duration.go │ │ │ └── duration_test.go │ │ ├── errors.generated.go │ │ └── session.go │ ├── command │ │ ├── command.go │ │ └── errors.generated.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 │ ├── geodata │ │ ├── attr.go │ │ ├── errors.generated.go │ │ ├── geodata.go │ │ ├── geodata_test.go │ │ ├── geodataproto.go │ │ ├── memconservative │ │ │ ├── cache.go │ │ │ ├── decode.go │ │ │ ├── decode_test.go │ │ │ ├── errors.generated.go │ │ │ └── memc.go │ │ └── standard │ │ │ ├── errors.generated.go │ │ │ └── standard.go │ ├── gun.go │ ├── http.go │ ├── http_test.go │ ├── init.go │ ├── json │ │ ├── reader.go │ │ └── reader_test.go │ ├── lint.go │ ├── loader.go │ ├── log.go │ ├── loopback.go │ ├── observatory.go │ ├── policy.go │ ├── policy_test.go │ ├── reverse.go │ ├── reverse_test.go │ ├── router.go │ ├── router_strategy.go │ ├── router_test.go │ ├── rule │ │ ├── errors.generated.go │ │ ├── rule.go │ │ └── rule_test.go │ ├── serial │ │ ├── errors.generated.go │ │ ├── loader.go │ │ ├── loader_test.go │ │ └── serial.go │ ├── services.go │ ├── shadowsocks.go │ ├── shadowsocks_test.go │ ├── socks.go │ ├── socks_test.go │ ├── transport.go │ ├── transport_authenticators.go │ ├── transport_internet.go │ ├── transport_test.go │ ├── trojan.go │ ├── v2ray.go │ ├── v2ray_test.go │ ├── vmess.go │ └── vmess_test.go ├── control │ ├── api.go │ ├── cert.go │ ├── certchainhash.go │ ├── command.go │ ├── config.go │ ├── control.go │ ├── errors.generated.go │ ├── fetch.go │ ├── love.go │ ├── main │ │ └── main.go │ ├── tlsping.go │ ├── uuid.go │ └── verify.go ├── vformat │ └── main.go └── vprotogen │ └── main.go ├── main ├── confloader │ ├── confloader.go │ ├── errors.generated.go │ └── external │ │ ├── errors.generated.go │ │ └── external.go ├── distro │ ├── all │ │ └── all.go │ └── debug │ │ └── debug.go ├── errors.generated.go ├── json │ ├── config_json.go │ └── errors.generated.go ├── jsonem │ ├── errors.generated.go │ └── jsonem.go ├── main.go └── main_test.go ├── mocks.go ├── proto.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 ├── 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 ├── loopback │ ├── config.go │ ├── config.pb.go │ ├── config.proto │ ├── errors.generated.go │ └── loopback.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 ├── 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 └── vmess │ ├── account.go │ ├── account.pb.go │ ├── account.proto │ ├── aead │ ├── authid.go │ ├── authid_test.go │ ├── consts.go │ ├── encrypt.go │ ├── encrypt_test.go │ ├── kdf.go │ └── kdf_test.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 ├── release ├── config │ ├── config.json │ ├── systemd │ │ └── system │ │ │ ├── v2ray.service │ │ │ └── v2ray@.service │ ├── sysusers.d │ │ └── v2ray.conf │ └── tmpfiles.d │ │ └── v2ray.conf ├── debian │ ├── changelog │ ├── control │ ├── copyright │ ├── rules │ ├── source │ │ └── format │ ├── v2ray-docs.docs │ ├── v2ray-domain-list-community.install │ ├── v2ray-geoip.install │ ├── v2ray.install │ ├── v2ray.service │ └── v2ray@.service ├── extra │ └── browserforwarder │ │ ├── index.html │ │ └── index.js ├── install-release.sh ├── requestsign.sh └── user-package.sh ├── testing ├── 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 ├── 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 │ │ │ ├── conn.go │ │ │ ├── customSeviceName.go │ │ │ ├── encoding.go │ │ │ ├── errors.generated.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_linux.go │ ├── system_dialer_other.go │ ├── system_dns_android.go │ ├── system_dns_android_test.go │ ├── system_listener.go │ ├── system_listener_test.go │ ├── tagged │ │ ├── tagged.go │ │ └── taggedimpl │ │ │ ├── errors.generated.go │ │ │ ├── impl.go │ │ │ └── taggedimpl.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 │ │ ├── pin.go │ │ ├── pin_test.go │ │ └── tls.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 │ │ ├── connforwarder.go │ │ ├── dialer.go │ │ ├── errors.generated.go │ │ ├── hub.go │ │ ├── ws.go │ │ └── ws_test.go ├── link.go └── pipe │ ├── impl.go │ ├── pipe.go │ ├── pipe_test.go │ ├── reader.go │ └── writer.go ├── v2ray.go └── v2ray_test.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | open-pull-requests-limit: 10 13 | 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "daily" 18 | -------------------------------------------------------------------------------- /.github/linters/.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 5m 3 | skip-files: 4 | - generated.* 5 | 6 | issues: 7 | new: true 8 | exclude-rules: 9 | - linters: 10 | - staticcheck 11 | text: "SA1019:" 12 | 13 | linters: 14 | enable: 15 | - asciicheck 16 | - bodyclose 17 | - depguard 18 | - gocritic 19 | - gofmt 20 | - gofumpt 21 | - goimports 22 | - golint 23 | - goprintffuncname 24 | - gosimple 25 | - govet 26 | - ineffassign 27 | - misspell 28 | - nakedret 29 | - rowserrcheck 30 | - staticcheck 31 | - structcheck 32 | - stylecheck 33 | - typecheck 34 | - unconvert 35 | - unparam 36 | - varcheck 37 | - whitespace 38 | disable: 39 | - deadcode 40 | - errcheck 41 | - unused 42 | 43 | linters-settings: 44 | goimports: 45 | local-prefixes: github.com/Shadowsocks-NET/v2ray-go 46 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: Linter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - v* 8 | paths: 9 | - "**/*.go" 10 | - ".github/workflows/linter.yml" 11 | pull_request: 12 | types: [opened, synchronize, reopened] 13 | paths: 14 | - "**/*.go" 15 | - ".github/workflows/linter.yml" 16 | 17 | jobs: 18 | lint: 19 | if: github.repository == 'Shadowsocks-NET/v2ray-go' 20 | runs-on: ubuntu-latest 21 | container: 22 | image: archlinux/archlinux:base-devel 23 | steps: 24 | - uses: actions/checkout@v3 25 | 26 | - name: Install dependencies 27 | run: | 28 | pacman -Syu --needed --noconfirm go protobuf 29 | 30 | - name: golangci-lint 31 | uses: golangci/golangci-lint-action@v3 32 | with: 33 | version: latest 34 | args: --config=.github/linters/.golangci.yml 35 | only-new-issues: true 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | *.DS_Store 18 | .idea 19 | *.zip 20 | *.tar.gz 21 | v2ray 22 | v2ctl 23 | mockgen 24 | vprotogen 25 | !infra/vprotogen/ 26 | errorgen 27 | !common/errors/errorgen/ 28 | *.dat 29 | -------------------------------------------------------------------------------- /annotations.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | // Annotation is a concept in V2Ray. This struct is only for documentation. It is not used anywhere. 4 | // Annotations begin with "v2ray:" 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 | // * v2ray:api:beta for types or functions that are ready for use, but maybe changed in the future. 9 | // * v2ray:api:stable for types or functions with guarantee of backward compatibility. 10 | // * v2ray: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 | -------------------------------------------------------------------------------- /app/app.go: -------------------------------------------------------------------------------- 1 | // Package app contains feature implementations of V2Ray. The features may be enabled during runtime. 2 | package app 3 | -------------------------------------------------------------------------------- /app/browserforwarder/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.app.browserforwarder; 4 | 5 | option csharp_namespace = "V2Ray.Core.App.Browserforwarder"; 6 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/browserforwarder"; 7 | option java_package = "com.v2ray.core.app.browserforwarder"; 8 | option java_multiple_files = true; 9 | 10 | // Config is the settings for BrowserForwarder. 11 | message Config { 12 | string listen_addr = 1; 13 | int32 listen_port = 2; 14 | } -------------------------------------------------------------------------------- /app/browserforwarder/errors.generated.go: -------------------------------------------------------------------------------- 1 | package browserforwarder 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.app.commander; 4 | option csharp_namespace = "V2Ray.Core.App.Commander"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/commander"; 6 | option java_package = "com.v2ray.core.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 v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package commander 5 | 6 | import ( 7 | "context" 8 | 9 | "google.golang.org/grpc" 10 | "google.golang.org/grpc/reflection" 11 | 12 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 13 | ) 14 | 15 | // Service is a Commander service. 16 | type Service interface { 17 | // Register registers the service itself to a gRPC server. 18 | Register(*grpc.Server) 19 | } 20 | 21 | type reflectionService struct{} 22 | 23 | func (r reflectionService) Register(s *grpc.Server) { 24 | reflection.Register(s) 25 | } 26 | 27 | func init() { 28 | common.Must(common.RegisterConfig((*ReflectionConfig)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) { 29 | return reflectionService{}, nil 30 | })) 31 | } 32 | -------------------------------------------------------------------------------- /app/dispatcher/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.app.dispatcher; 4 | option csharp_namespace = "V2Ray.Core.App.Dispatcher"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/dispatcher"; 6 | option java_package = "com.v2ray.core.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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package dispatcher 5 | 6 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 7 | -------------------------------------------------------------------------------- /app/dispatcher/errors.generated.go: -------------------------------------------------------------------------------- 1 | package dispatcher 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package dispatcher 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/features/stats" 10 | ) 11 | 12 | type SizeStatWriter struct { 13 | Counter stats.Counter 14 | Writer buf.Writer 15 | } 16 | 17 | func (w *SizeStatWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { 18 | w.Counter.Add(int64(mb.Len())) 19 | return w.Writer.WriteMultiBuffer(mb) 20 | } 21 | 22 | func (w *SizeStatWriter) Close() error { 23 | return common.Close(w.Writer) 24 | } 25 | 26 | func (w *SizeStatWriter) Interrupt() { 27 | common.Interrupt(w.Writer) 28 | } 29 | -------------------------------------------------------------------------------- /app/dispatcher/stats_test.go: -------------------------------------------------------------------------------- 1 | package dispatcher_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/Shadowsocks-NET/v2ray-go/v4/app/dispatcher" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/errors.generated.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package fakedns 5 | 6 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 7 | -------------------------------------------------------------------------------- /app/dns/fakedns/fakedns.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.app.dns.fakedns; 4 | option csharp_namespace = "V2Ray.Core.App.Dns.Fakedns"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/dns/fakedns"; 6 | option java_package = "com.v2ray.core.app.dns.fakedns"; 7 | option java_multiple_files = true; 8 | 9 | message FakeDnsPool{ 10 | string ip_pool = 1; //CIDR of IP pool used as fake DNS IP 11 | int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address 12 | } 13 | 14 | message FakeDnsPoolMulti{ 15 | repeated FakeDnsPool pools = 1; 16 | } -------------------------------------------------------------------------------- /app/dns/nameserver_local_test.go: -------------------------------------------------------------------------------- 1 | package dns_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | . "github.com/Shadowsocks-NET/v2ray-go/v4/app/dns" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/features/dns" 12 | ) 13 | 14 | func TestLocalNameServer(t *testing.T) { 15 | s := NewLocalNameServer() 16 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 17 | ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{ 18 | IPv4Enable: true, 19 | IPv6Enable: true, 20 | }, false) 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 | core "github.com/Shadowsocks-NET/v2ray-go/v4" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/app/dispatcher" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/app/log" 10 | . "github.com/Shadowsocks-NET/v2ray-go/v4/app/log/command" 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/app/proxyman" 12 | _ "github.com/Shadowsocks-NET/v2ray-go/v4/app/proxyman/inbound" 13 | _ "github.com/Shadowsocks-NET/v2ray-go/v4/app/proxyman/outbound" 14 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 15 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/serial" 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 v2ray.core.app.log.command; 4 | option csharp_namespace = "V2Ray.Core.App.Log.Command"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/log/command"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.app.log; 4 | option csharp_namespace = "V2Ray.Core.App.Log"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/log"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.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 | } 26 | -------------------------------------------------------------------------------- /app/log/errors.generated.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/observatory/command/command.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.app.observatory.command; 4 | option csharp_namespace = "V2Ray.Core.App.Observatory.Command"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/observatory/command"; 6 | option java_package = "com.v2ray.core.app.observatory.command"; 7 | option java_multiple_files = true; 8 | 9 | import "app/observatory/config.proto"; 10 | 11 | message GetOutboundStatusRequest { 12 | } 13 | 14 | message GetOutboundStatusResponse { 15 | v2ray.core.app.observatory.ObservationResult status = 1; 16 | } 17 | 18 | service ObservatoryService { 19 | rpc GetOutboundStatus(GetOutboundStatusRequest) 20 | returns (GetOutboundStatusResponse) {} 21 | } 22 | 23 | 24 | message Config {} -------------------------------------------------------------------------------- /app/observatory/errors.generated.go: -------------------------------------------------------------------------------- 1 | package observatory 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/observatory/explainErrors.go: -------------------------------------------------------------------------------- 1 | package observatory 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common/errors" 4 | 5 | type errorCollector struct { 6 | errors *errors.Error 7 | } 8 | 9 | func (e *errorCollector) SubmitError(err error) { 10 | if e.errors == nil { 11 | e.errors = newError("underlying connection error").Base(err) 12 | return 13 | } 14 | e.errors = e.errors.Base(newError("underlying connection error").Base(err)) 15 | } 16 | 17 | func newErrorCollector() *errorCollector { 18 | return &errorCollector{} 19 | } 20 | 21 | func (e *errorCollector) UnderlyingError() error { 22 | if e.errors == nil { 23 | return newError("failed to produce report") 24 | } 25 | return e.errors 26 | } 27 | -------------------------------------------------------------------------------- /app/observatory/observatory.go: -------------------------------------------------------------------------------- 1 | package observatory 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /app/policy/errors.generated.go: -------------------------------------------------------------------------------- 1 | package policy 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 5 | -------------------------------------------------------------------------------- /app/proxyman/command/doc.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /app/proxyman/command/errors.generated.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/inbound/errors.generated.go: -------------------------------------------------------------------------------- 1 | package inbound 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package reverse 5 | 6 | import ( 7 | "crypto/rand" 8 | "io" 9 | 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/dice" 11 | ) 12 | 13 | func (c *Control) FillInRandom() { 14 | randomLength := dice.Roll(64) 15 | c.Random = make([]byte, randomLength) 16 | io.ReadFull(rand.Reader, c.Random) 17 | } 18 | -------------------------------------------------------------------------------- /app/reverse/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.app.reverse; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Reverse"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/reverse"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/app/reverse" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/command/errors.generated.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.app.stats; 4 | option csharp_namespace = "V2Ray.Core.App.Stats"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/app/stats"; 6 | option java_package = "com.v2ray.core.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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package stats 5 | 6 | import "sync/atomic" 7 | 8 | // Counter is an implementation of stats.Counter. 9 | type Counter struct { 10 | value int64 11 | } 12 | 13 | // Value implements stats.Counter. 14 | func (c *Counter) Value() int64 { 15 | return atomic.LoadInt64(&c.value) 16 | } 17 | 18 | // Set implements stats.Counter. 19 | func (c *Counter) Set(newValue int64) int64 { 20 | return atomic.SwapInt64(&c.value, newValue) 21 | } 22 | 23 | // Add implements stats.Counter. 24 | func (c *Counter) Add(delta int64) int64 { 25 | return atomic.AddInt64(&c.value, delta) 26 | } 27 | -------------------------------------------------------------------------------- /app/stats/counter_test.go: -------------------------------------------------------------------------------- 1 | package stats_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | . "github.com/Shadowsocks-NET/v2ray-go/v4/app/stats" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/antireplay/antireplay.go: -------------------------------------------------------------------------------- 1 | package antireplay 2 | 3 | type GeneralizedReplayFilter interface { 4 | Interval() int64 5 | Check(sum []byte) bool 6 | } 7 | -------------------------------------------------------------------------------- /common/antireplay/bloomring.go: -------------------------------------------------------------------------------- 1 | package antireplay 2 | 3 | import ( 4 | "sync" 5 | 6 | ss_bloomring "github.com/v2fly/ss-bloomring" 7 | ) 8 | 9 | type BloomRing struct { 10 | *ss_bloomring.BloomRing 11 | lock *sync.Mutex 12 | } 13 | 14 | func (b BloomRing) Interval() int64 { 15 | return 9999999 16 | } 17 | 18 | func (b BloomRing) Check(sum []byte) bool { 19 | b.lock.Lock() 20 | defer b.lock.Unlock() 21 | if b.Test(sum) { 22 | return false 23 | } 24 | b.Add(sum) 25 | return true 26 | } 27 | 28 | func NewBloomRing() BloomRing { 29 | const ( 30 | DefaultSFCapacity = 1e6 31 | // FalsePositiveRate 32 | DefaultSFFPR = 1e-6 33 | DefaultSFSlot = 10 34 | ) 35 | return BloomRing{ss_bloomring.NewBloomRing(DefaultSFSlot, DefaultSFCapacity, DefaultSFFPR), &sync.Mutex{}} 36 | } 37 | -------------------------------------------------------------------------------- /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/Shadowsocks-NET/v2ray-go/v4/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/buf/buf.go: -------------------------------------------------------------------------------- 1 | // Package buf provides a light-weight memory allocation mechanism. 2 | package buf 3 | 4 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 5 | -------------------------------------------------------------------------------- /common/buf/errors.generated.go: -------------------------------------------------------------------------------- 1 | package buf 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !windows && !wasm && !illumos 2 | // +build !windows,!wasm,!illumos 3 | 4 | package buf 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | type posixReader struct { 12 | iovecs []syscall.Iovec 13 | } 14 | 15 | func (r *posixReader) Init(bs []*Buffer) { 16 | iovecs := r.iovecs 17 | if iovecs == nil { 18 | iovecs = make([]syscall.Iovec, 0, len(bs)) 19 | } 20 | for idx, b := range bs { 21 | iovecs = append(iovecs, syscall.Iovec{ 22 | Base: &(b.v[0]), 23 | }) 24 | iovecs[idx].SetLen(int(Size)) 25 | } 26 | r.iovecs = iovecs 27 | } 28 | 29 | func (r *posixReader) Read(fd uintptr) int32 { 30 | n, _, e := syscall.Syscall(syscall.SYS_READV, fd, uintptr(unsafe.Pointer(&r.iovecs[0])), uintptr(len(r.iovecs))) 31 | if e != 0 { 32 | return -1 33 | } 34 | return int32(n) 35 | } 36 | 37 | func (r *posixReader) Clear() { 38 | for idx := range r.iovecs { 39 | r.iovecs[idx].Base = nil 40 | } 41 | r.iovecs = r.iovecs[:0] 42 | } 43 | 44 | func newMultiReader() multiReader { 45 | return &posixReader{} 46 | } 47 | -------------------------------------------------------------------------------- /common/buf/readv_reader_wasm.go: -------------------------------------------------------------------------------- 1 | //go:build wasm 2 | // +build wasm 3 | 4 | package buf 5 | 6 | import ( 7 | "io" 8 | "syscall" 9 | ) 10 | 11 | const useReadv = false 12 | 13 | func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) Reader { 14 | panic("not implemented") 15 | } 16 | -------------------------------------------------------------------------------- /common/buf/readv_unix.go: -------------------------------------------------------------------------------- 1 | //go:build illumos 2 | // +build illumos 3 | 4 | package buf 5 | 6 | import "golang.org/x/sys/unix" 7 | 8 | type unixReader struct { 9 | iovs [][]byte 10 | } 11 | 12 | func (r *unixReader) Init(bs []*Buffer) { 13 | iovs := r.iovs 14 | if iovs == nil { 15 | iovs = make([][]byte, 0, len(bs)) 16 | } 17 | for _, b := range bs { 18 | iovs = append(iovs, b.v) 19 | } 20 | r.iovs = iovs 21 | } 22 | 23 | func (r *unixReader) Read(fd uintptr) int32 { 24 | n, e := unix.Readv(int(fd), r.iovs) 25 | if e != nil { 26 | return -1 27 | } 28 | return int32(n) 29 | } 30 | 31 | func (r *unixReader) Clear() { 32 | r.iovs = r.iovs[:0] 33 | } 34 | 35 | func newMultiReader() multiReader { 36 | return &unixReader{} 37 | } 38 | -------------------------------------------------------------------------------- /common/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 V2Ray. 2 | package crypto 3 | 4 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 5 | -------------------------------------------------------------------------------- /common/crypto/errors.generated.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/drain/drain.go: -------------------------------------------------------------------------------- 1 | package drain 2 | 3 | import "io" 4 | 5 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 6 | 7 | type Drainer interface { 8 | AcknowledgeReceive(size int) 9 | Drain(reader io.Reader) error 10 | } 11 | -------------------------------------------------------------------------------- /common/drain/errors.generated.go: -------------------------------------------------------------------------------- 1 | package drain 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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.generated.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/errorgen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | func main() { 10 | pwd, err := os.Getwd() 11 | if err != nil { 12 | fmt.Println("can not get current working directory") 13 | os.Exit(1) 14 | } 15 | pkg := filepath.Base(pwd) 16 | if pkg == "v2ray-core" { 17 | pkg = "core" 18 | } 19 | 20 | file, err := os.OpenFile("errors.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0o644) 21 | if err != nil { 22 | fmt.Printf("Failed to generate errors.generated.go: %v", err) 23 | os.Exit(1) 24 | } 25 | defer file.Close() 26 | 27 | fmt.Fprintf(file, `package %s 28 | 29 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common/errors" 30 | 31 | type errPathObjHolder struct{} 32 | 33 | func newError(values ...interface{}) *errors.Error { 34 | return errors.New(values...).WithPathObj(errPathObjHolder{}) 35 | } 36 | `, pkg) 37 | } 38 | -------------------------------------------------------------------------------- /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 v2ray.core.common.log; 4 | option csharp_namespace = "V2Ray.Core.Common.Log"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/log"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common/log" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 | "os" 5 | "strings" 6 | "testing" 7 | "time" 8 | 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 11 | . "github.com/Shadowsocks-NET/v2ray-go/v4/common/log" 12 | ) 13 | 14 | func TestFileLogger(t *testing.T) { 15 | f, err := os.CreateTemp("", "vtest") 16 | common.Must(err) 17 | path := f.Name() 18 | common.Must(f.Close()) 19 | 20 | creator, err := CreateFileLogWriter(path) 21 | common.Must(err) 22 | 23 | handler := NewLogger(creator) 24 | handler.Handle(&GeneralMessage{Content: "Test Log"}) 25 | time.Sleep(2 * time.Second) 26 | 27 | common.Must(common.Close(handler)) 28 | 29 | f, err = os.Open(path) 30 | common.Must(err) 31 | defer f.Close() 32 | 33 | b, err := buf.ReadAllToBytes(f) 34 | common.Must(err) 35 | if !strings.Contains(string(b), "Test Log") { 36 | t.Fatal("Expect log text contains 'Test Log', but actually: ", string(b)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /common/mux/errors.generated.go: -------------------------------------------------------------------------------- 1 | package mux 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/mux" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 10 | ) 11 | 12 | func BenchmarkFrameWrite(b *testing.B) { 13 | frame := mux.FrameMetadata{ 14 | Target: net.TCPDestination(net.DomainAddress("www.v2fly.org"), 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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /common/mux/session_test.go: -------------------------------------------------------------------------------- 1 | package mux_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.common.net; 4 | option csharp_namespace = "V2Ray.Core.Common.Net"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/net"; 6 | option java_package = "com.v2ray.core.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 v2ray.core.common.net; 4 | option csharp_namespace = "V2Ray.Core.Common.Net"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/net"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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 3 | 4 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.common.net; 4 | option csharp_namespace = "V2Ray.Core.Common.Net"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/net"; 6 | option java_package = "com.v2ray.core.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 v2ray.core.common.net; 4 | option csharp_namespace = "V2Ray.Core.Common.Net"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/net"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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/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 | //go:build !windows 2 | // +build !windows 3 | 4 | package ctlcmd 5 | 6 | import "syscall" 7 | 8 | func getSysProcAttr() *syscall.SysProcAttr { 9 | return nil 10 | } 11 | -------------------------------------------------------------------------------- /common/platform/ctlcmd/attr_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package ctlcmd 5 | 6 | import "syscall" 7 | 8 | func getSysProcAttr() *syscall.SysProcAttr { 9 | return &syscall.SysProcAttr{ 10 | HideWindow: true, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /common/platform/ctlcmd/errors.generated.go: -------------------------------------------------------------------------------- 1 | package ctlcmd 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package platform 5 | 6 | import "path/filepath" 7 | 8 | func ExpandEnv(s string) string { 9 | // TODO 10 | return s 11 | } 12 | 13 | func LineSeparator() string { 14 | return "\r\n" 15 | } 16 | 17 | func GetToolLocation(file string) string { 18 | const name = "v2ray.location.tool" 19 | toolPath := EnvFlag{Name: name, AltName: NormalizeEnvName(name)}.GetValue(getExecutableDir) 20 | return filepath.Join(toolPath, file+".exe") 21 | } 22 | 23 | // GetAssetLocation search for `file` in the excutable dir 24 | func GetAssetLocation(file string) string { 25 | const name = "v2ray.location.asset" 26 | assetPath := NewEnvFlag(name).GetValue(getExecutableDir) 27 | return filepath.Join(assetPath, file) 28 | } 29 | -------------------------------------------------------------------------------- /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/Shadowsocks-NET/v2ray-go/v4/common" 7 | ) 8 | 9 | type SniffHeader struct{} 10 | 11 | func (h *SniffHeader) Protocol() string { 12 | return "bittorrent" 13 | } 14 | 15 | func (h *SniffHeader) Domain() string { 16 | return "" 17 | } 18 | 19 | var errNotBittorrent = errors.New("not bittorrent header") 20 | 21 | func SniffBittorrent(b []byte) (*SniffHeader, error) { 22 | if len(b) < 20 { 23 | return nil, common.ErrNoClue 24 | } 25 | 26 | if b[0] == 19 && string(b[1:20]) == "BitTorrent protocol" { 27 | return &SniffHeader{}, nil 28 | } 29 | 30 | return nil, errNotBittorrent 31 | } 32 | -------------------------------------------------------------------------------- /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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.common.protocol; 4 | option csharp_namespace = "V2Ray.Core.Common.Protocol"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common/protocol" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /common/protocol/server_spec.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.common.protocol; 4 | option csharp_namespace = "V2Ray.Core.Common.Protocol"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.common.net.IPOrDomain address = 1; 14 | uint32 port = 2; 15 | repeated v2ray.core.common.protocol.User user = 3; 16 | } 17 | -------------------------------------------------------------------------------- /common/protocol/time.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/buf" 5 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.common.protocol; 4 | option csharp_namespace = "V2Ray.Core.Common.Protocol"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.common.serial.TypedMessage account = 3; 19 | } 20 | -------------------------------------------------------------------------------- /common/retry/errors.generated.go: -------------------------------------------------------------------------------- 1 | package retry 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/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 v2ray.core.common.serial; 4 | option csharp_namespace = "V2Ray.Core.Common.Serial"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/common/serial"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/strmatcher" 8 | ) 9 | 10 | func TestFullMatcherGroup(t *testing.T) { 11 | g := new(FullMatcherGroup) 12 | g.Add("v2fly.org", 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: "v2fly.org", 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("v2fly.org") 47 | if len(r) != 0 { 48 | t.Error("Expect [], but ", r) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /common/strmatcher/matchers.go: -------------------------------------------------------------------------------- 1 | package strmatcher 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | type fullMatcher string 9 | 10 | func (m fullMatcher) Match(s string) bool { 11 | return string(m) == s 12 | } 13 | 14 | func (m fullMatcher) String() string { 15 | return "full:" + string(m) 16 | } 17 | 18 | type substrMatcher string 19 | 20 | func (m substrMatcher) Match(s string) bool { 21 | return strings.Contains(s, string(m)) 22 | } 23 | 24 | func (m substrMatcher) String() string { 25 | return "keyword:" + string(m) 26 | } 27 | 28 | type domainMatcher string 29 | 30 | func (m domainMatcher) Match(s string) bool { 31 | pattern := string(m) 32 | if !strings.HasSuffix(s, pattern) { 33 | return false 34 | } 35 | return len(s) == len(pattern) || s[len(s)-len(pattern)-1] == '.' 36 | } 37 | 38 | func (m domainMatcher) String() string { 39 | return "domain:" + string(m) 40 | } 41 | 42 | type regexMatcher struct { 43 | pattern *regexp.Regexp 44 | } 45 | 46 | func (m *regexMatcher) Match(s string) bool { 47 | return m.pattern.MatchString(s) 48 | } 49 | 50 | func (m *regexMatcher) String() string { 51 | return "regexp:" + m.pattern.String() 52 | } 53 | -------------------------------------------------------------------------------- /common/task/common.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | "sync/atomic" 5 | "testing" 6 | "time" 7 | 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/common/task" 10 | ) 11 | 12 | func TestPeriodicTaskStop(t *testing.T) { 13 | var value uint64 14 | task := &Periodic{ 15 | Interval: time.Second * 2, 16 | Execute: func() error { 17 | atomic.AddUint64(&value, 1) 18 | return nil 19 | }, 20 | } 21 | common.Must(task.Start()) 22 | time.Sleep(time.Second * 5) 23 | common.Must(task.Close()) 24 | value1 := atomic.LoadUint64(&value) 25 | if value1 != 3 { 26 | t.Fatal("expected 3, but got ", value1) 27 | } 28 | 29 | time.Sleep(time.Second * 4) 30 | value2 := atomic.LoadUint64(&value) 31 | if value2 != 3 { 32 | t.Fatal("expected 3, but got ", value2) 33 | } 34 | 35 | common.Must(task.Start()) 36 | time.Sleep(time.Second * 3) 37 | value3 := atomic.LoadUint64(&value) 38 | if value3 != 5 { 39 | t.Fatal("Expected 5, but ", value3) 40 | } 41 | common.Must(task.Close()) 42 | } 43 | -------------------------------------------------------------------------------- /common/task/task.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 8 | ) 9 | 10 | type TConfig struct { 11 | value int 12 | } 13 | 14 | type YConfig struct { 15 | value string 16 | } 17 | 18 | func TestObjectCreation(t *testing.T) { 19 | f := func(ctx context.Context, t interface{}) (interface{}, error) { 20 | return func() int { 21 | return t.(*TConfig).value 22 | }, nil 23 | } 24 | 25 | Must(RegisterConfig((*TConfig)(nil), f)) 26 | err := RegisterConfig((*TConfig)(nil), f) 27 | if err == nil { 28 | t.Error("expect non-nil error, but got nil") 29 | } 30 | 31 | g, err := CreateObject(context.Background(), &TConfig{value: 2}) 32 | Must(err) 33 | if v := g.(func() int)(); v != 2 { 34 | t.Error("expect return value 2, but got ", v) 35 | } 36 | 37 | _, err = CreateObject(context.Background(), &YConfig{value: "T"}) 38 | if err == nil { 39 | t.Error("expect non-nil error, but got nil") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /context_test.go: -------------------------------------------------------------------------------- 1 | package core_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | _ "unsafe" 7 | 8 | . "github.com/Shadowsocks-NET/v2ray-go/v4" 9 | ) 10 | 11 | func TestFromContextPanic(t *testing.T) { 12 | defer func() { 13 | r := recover() 14 | if r == nil { 15 | t.Error("expect panic, but nil") 16 | } 17 | }() 18 | 19 | MustFromContext(context.Background()) 20 | } 21 | -------------------------------------------------------------------------------- /errors.generated.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/dns/fakedns.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 5 | "github.com/Shadowsocks-NET/v2ray-go/v4/features" 6 | ) 7 | 8 | type FakeDNSEngine interface { 9 | features.Feature 10 | GetFakeIPForDomain(domain string) []net.Address 11 | GetDomainFromFakeDNS(ip net.Address) string 12 | } 13 | 14 | type FakeDNSEngineRev0 interface { 15 | FakeDNSEngine 16 | IsIPInIPPool(ip net.Address) bool 17 | GetFakeIPForDomain3(domain string, IPv4, IPv6 bool) []net.Address 18 | } 19 | -------------------------------------------------------------------------------- /features/dns/localdns/errors.generated.go: -------------------------------------------------------------------------------- 1 | package localdns 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/extension/browser.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | ) 7 | 8 | type BrowserForwarder interface { 9 | DialWebsocket(url string, header http.Header) (io.ReadWriteCloser, error) 10 | } 11 | 12 | func BrowserForwarderType() interface{} { 13 | return (*BrowserForwarder)(nil) 14 | } 15 | -------------------------------------------------------------------------------- /features/extension/contextreceiver.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import "context" 4 | 5 | type ContextReceiver interface { 6 | InjectContext(ctx context.Context) 7 | } 8 | -------------------------------------------------------------------------------- /features/extension/observatory.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/golang/protobuf/proto" 7 | 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/features" 9 | ) 10 | 11 | type Observatory interface { 12 | features.Feature 13 | 14 | GetObservation(ctx context.Context) (proto.Message, error) 15 | } 16 | 17 | func ObservatoryType() interface{} { 18 | return (*Observatory)(nil) 19 | } 20 | -------------------------------------------------------------------------------- /features/feature.go: -------------------------------------------------------------------------------- 1 | package features 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common" 4 | 5 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 6 | 7 | // Feature is the interface for V2Ray 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 | // DefaultManager is the implementation of the Manager. 4 | type DefaultManager struct{} 5 | 6 | // Type implements common.HasType. 7 | func (DefaultManager) Type() interface{} { 8 | return ManagerType() 9 | } 10 | 11 | // ForLevel implements Manager. 12 | func (DefaultManager) ForLevel(level uint32) Session { 13 | return SessionDefault() 14 | } 15 | 16 | // ForSystem implements Manager. 17 | func (DefaultManager) ForSystem() System { 18 | return System{} 19 | } 20 | 21 | // Start implements common.Runnable. 22 | func (DefaultManager) Start() error { 23 | return nil 24 | } 25 | 26 | // Close implements common.Closable. 27 | func (DefaultManager) Close() error { 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /features/routing/dispatcher.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/features" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 V2Ray instance to make V2Ray function properly. 13 | // 14 | // v2ray: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 | // v2ray: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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors" 4 | 5 | type errPathObjHolder struct{} 6 | 7 | func newError(values ...interface{}) *errors.Error { 8 | return errors.New(values...).WithPathObj(errPathObjHolder{}) 9 | } 10 | -------------------------------------------------------------------------------- /format.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | //go:generate go install -v github.com/daixiang0/gci@latest 4 | //go:generate go run ./infra/vformat/ 5 | -------------------------------------------------------------------------------- /infra/conf/blackhole_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/serial" 7 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/browser_forwarder.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/golang/protobuf/proto" 7 | 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/app/browserforwarder" 9 | ) 10 | 11 | type BrowserForwarderConfig struct { 12 | ListenAddr string `json:"listenAddr"` 13 | ListenPort int32 `json:"listenPort"` 14 | } 15 | 16 | func (b *BrowserForwarderConfig) Build() (proto.Message, error) { 17 | b.ListenAddr = strings.TrimSpace(b.ListenAddr) 18 | if b.ListenAddr != "" && b.ListenPort == 0 { 19 | b.ListenPort = 54321 20 | } 21 | return &browserforwarder.Config{ 22 | ListenAddr: b.ListenAddr, 23 | ListenPort: b.ListenPort, 24 | }, nil 25 | } 26 | -------------------------------------------------------------------------------- /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/cfgcommon/duration/duration.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type Duration int64 10 | 11 | func (d *Duration) MarshalJSON() ([]byte, error) { 12 | dr := time.Duration(*d) 13 | return json.Marshal(dr.String()) 14 | } 15 | 16 | func (d *Duration) UnmarshalJSON(b []byte) error { 17 | var v interface{} 18 | if err := json.Unmarshal(b, &v); err != nil { 19 | return err 20 | } 21 | switch value := v.(type) { 22 | case string: 23 | var err error 24 | dr, err := time.ParseDuration(value) 25 | if err != nil { 26 | return err 27 | } 28 | *d = Duration(dr) 29 | return nil 30 | default: 31 | return fmt.Errorf("invalid duration: %v", v) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /infra/conf/cfgcommon/duration/duration_test.go: -------------------------------------------------------------------------------- 1 | package duration_test 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | "time" 7 | 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf/cfgcommon/duration" 9 | ) 10 | 11 | type testWithDuration struct { 12 | Duration duration.Duration 13 | } 14 | 15 | func TestDurationJSON(t *testing.T) { 16 | expected := &testWithDuration{ 17 | Duration: duration.Duration(time.Hour), 18 | } 19 | data, err := json.Marshal(expected) 20 | if err != nil { 21 | t.Error(err) 22 | return 23 | } 24 | actual := &testWithDuration{} 25 | err = json.Unmarshal(data, &actual) 26 | if err != nil { 27 | t.Error(err) 28 | return 29 | } 30 | if actual.Duration != expected.Duration { 31 | t.Errorf("expected: %s, actual: %s", time.Duration(expected.Duration), time.Duration(actual.Duration)) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /infra/conf/cfgcommon/errors.generated.go: -------------------------------------------------------------------------------- 1 | package cfgcommon 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/command/errors.generated.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /infra/conf/dns_proxy.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf/cfgcommon" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/dns" 9 | ) 10 | 11 | type DNSOutboundConfig struct { 12 | Network cfgcommon.Network `json:"network"` 13 | Address *cfgcommon.Address `json:"address"` 14 | Port uint16 `json:"port"` 15 | } 16 | 17 | func (c *DNSOutboundConfig) Build() (proto.Message, error) { 18 | config := &dns.Config{ 19 | Server: &net.Endpoint{ 20 | Network: c.Network.Build(), 21 | Port: uint32(c.Port), 22 | }, 23 | } 24 | if c.Address != nil { 25 | config.Server.Address = c.Address.Build() 26 | } 27 | return config, nil 28 | } 29 | -------------------------------------------------------------------------------- /infra/conf/dns_proxy_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf/cfgcommon" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/dokodemo" 8 | ) 9 | 10 | type DokodemoConfig struct { 11 | Host *cfgcommon.Address `json:"address"` 12 | PortValue uint16 `json:"port"` 13 | NetworkList *cfgcommon.NetworkList `json:"network"` 14 | Redirect bool `json:"followRedirect"` 15 | UserLevel uint32 `json:"userLevel"` 16 | } 17 | 18 | func (v *DokodemoConfig) Build() (proto.Message, error) { 19 | config := new(dokodemo.Config) 20 | if v.Host != nil { 21 | config.Address = v.Host.Build() 22 | } 23 | config.Port = uint32(v.PortValue) 24 | config.Networks = v.NetworkList.Build() 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/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 | FollowRedirect: true, 36 | UserLevel: 1, 37 | }, 38 | }, 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /infra/conf/errors.generated.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol" 8 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 | DestinationOverride: &freedom.DestinationOverride{ 28 | Server: &protocol.ServerEndpoint{ 29 | Address: &net.IPOrDomain{ 30 | Address: &net.IPOrDomain_Ip{ 31 | Ip: []byte{127, 0, 0, 1}, 32 | }, 33 | }, 34 | Port: 3366, 35 | }, 36 | }, 37 | UserLevel: 1, 38 | }, 39 | }, 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /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 | 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 10 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 11 | ) 12 | 13 | func loadJSON(creator func() Buildable) func(string) (proto.Message, error) { 14 | return func(s string) (proto.Message, error) { 15 | instance := creator() 16 | if err := json.Unmarshal([]byte(s), instance); err != nil { 17 | return nil, err 18 | } 19 | return instance.Build() 20 | } 21 | } 22 | 23 | type TestCase struct { 24 | Input string 25 | Parser func(string) (proto.Message, error) 26 | Output proto.Message 27 | } 28 | 29 | func runMultiTestCase(t *testing.T, testCases []TestCase) { 30 | for _, testCase := range testCases { 31 | actual, err := testCase.Parser(testCase.Input) 32 | common.Must(err) 33 | if !proto.Equal(actual, testCase.Output) { 34 | t.Fatalf("Failed in test case:\n%s\nActual:\n%v\nExpected:\n%v", testCase.Input, actual, testCase.Output) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /infra/conf/geodata/errors.generated.go: -------------------------------------------------------------------------------- 1 | package geodata 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/geodata/geodataproto.go: -------------------------------------------------------------------------------- 1 | package geodata 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/app/router" 4 | 5 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 6 | 7 | type LoaderImplementation interface { 8 | LoadSite(filename, list string) ([]*router.Domain, error) 9 | LoadIP(filename, country string) ([]*router.CIDR, error) 10 | } 11 | 12 | type Loader interface { 13 | LoaderImplementation 14 | LoadGeoSite(list string) ([]*router.Domain, error) 15 | LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) 16 | LoadGeoIP(country string) ([]*router.CIDR, error) 17 | } 18 | -------------------------------------------------------------------------------- /infra/conf/geodata/memconservative/errors.generated.go: -------------------------------------------------------------------------------- 1 | package memconservative 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/geodata/standard/errors.generated.go: -------------------------------------------------------------------------------- 1 | package standard 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/gun.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/grpc" 7 | ) 8 | 9 | type GunConfig struct { 10 | ServiceName string `json:"serviceName"` 11 | } 12 | 13 | func (g GunConfig) Build() (proto.Message, error) { 14 | return &grpc.Config{ServiceName: g.ServiceName}, nil 15 | } 16 | -------------------------------------------------------------------------------- /infra/conf/http_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 | }, 36 | }, 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /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/loopback.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/loopback" 7 | ) 8 | 9 | type LoopbackConfig struct { 10 | InboundTag string `json:"inboundTag"` 11 | } 12 | 13 | func (l LoopbackConfig) Build() (proto.Message, error) { 14 | return &loopback.Config{InboundTag: l.InboundTag}, nil 15 | } 16 | -------------------------------------------------------------------------------- /infra/conf/observatory.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/app/observatory" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf/cfgcommon/duration" 8 | ) 9 | 10 | type ObservatoryConfig struct { 11 | SubjectSelector []string `json:"subjectSelector"` 12 | ProbeURL string `json:"probeURL"` 13 | ProbeInterval duration.Duration `json:"probeInterval"` 14 | } 15 | 16 | func (o *ObservatoryConfig) Build() (proto.Message, error) { 17 | return &observatory.Config{SubjectSelector: o.SubjectSelector, ProbeUrl: o.ProbeURL, ProbeInterval: int64(o.ProbeInterval)}, nil 18 | } 19 | -------------------------------------------------------------------------------- /infra/conf/policy_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 7 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/app/reverse" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/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.v2fly.org" 21 | }] 22 | }`, 23 | Parser: loadJSON(creator), 24 | Output: &reverse.Config{ 25 | BridgeConfig: []*reverse.BridgeConfig{ 26 | {Tag: "test", Domain: "test.v2fly.org"}, 27 | }, 28 | }, 29 | }, 30 | { 31 | Input: `{ 32 | "portals": [{ 33 | "tag": "test", 34 | "domain": "test.v2fly.org" 35 | }] 36 | }`, 37 | Parser: loadJSON(creator), 38 | Output: &reverse.Config{ 39 | PortalConfig: []*reverse.PortalConfig{ 40 | {Tag: "test", Domain: "test.v2fly.org"}, 41 | }, 42 | }, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /infra/conf/router_strategy.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | const ( 4 | strategyRandom string = "random" 5 | strategyLeastPing string = "leastping" 6 | ) 7 | -------------------------------------------------------------------------------- /infra/conf/rule/errors.generated.go: -------------------------------------------------------------------------------- 1 | package rule 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/errors.generated.go: -------------------------------------------------------------------------------- 1 | package serial 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /infra/conf/services.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/golang/protobuf/jsonpb" 7 | "github.com/jhump/protoreflect/desc" 8 | "github.com/jhump/protoreflect/dynamic" 9 | 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/serial" 11 | ) 12 | 13 | func (c *Config) BuildServices(service map[string]*json.RawMessage) ([]*serial.TypedMessage, error) { 14 | var ret []*serial.TypedMessage 15 | for k, v := range service { 16 | message, err := desc.LoadMessageDescriptor(k) 17 | if err != nil || message == nil { 18 | return nil, newError("Cannot find service", k, "").Base(err) 19 | } 20 | 21 | serviceConfig := dynamic.NewMessage(message) 22 | 23 | if err := serviceConfig.UnmarshalJSONPB(&jsonpb.Unmarshaler{AllowUnknownFields: false}, *v); err != nil { 24 | return nil, newError("Cannot interpret service configure file", k, "").Base(err) 25 | } 26 | 27 | ret = append(ret, serial.ToTypedMessage(serviceConfig)) 28 | } 29 | return ret, nil 30 | } 31 | -------------------------------------------------------------------------------- /infra/conf/shadowsocks_test.go: -------------------------------------------------------------------------------- 1 | package conf_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/serial" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/infra/conf" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/shadowsocks" 11 | ) 12 | 13 | func TestShadowsocksServerConfigParsing(t *testing.T) { 14 | creator := func() Buildable { 15 | return new(ShadowsocksServerConfig) 16 | } 17 | 18 | runMultiTestCase(t, []TestCase{ 19 | { 20 | Input: `{ 21 | "method": "aes-256-GCM", 22 | "password": "v2ray-password" 23 | }`, 24 | Parser: loadJSON(creator), 25 | Output: &shadowsocks.ServerConfig{ 26 | User: &protocol.User{ 27 | Account: serial.ToTypedMessage(&shadowsocks.Account{ 28 | CipherType: shadowsocks.CipherType_AES_256_GCM, 29 | Password: "v2ray-password", 30 | }), 31 | }, 32 | Network: []net.Network{net.Network_TCP}, 33 | }, 34 | }, 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /infra/control/command.go: -------------------------------------------------------------------------------- 1 | package control 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | type Description struct { 11 | Short string 12 | Usage []string 13 | } 14 | 15 | type Command interface { 16 | Name() string 17 | Description() Description 18 | Execute(args []string) error 19 | } 20 | 21 | var ( 22 | commandRegistry = make(map[string]Command) 23 | ctllog = log.New(os.Stderr, "v2ctl> ", 0) 24 | ) 25 | 26 | func RegisterCommand(cmd Command) error { 27 | entry := strings.ToLower(cmd.Name()) 28 | if entry == "" { 29 | return newError("empty command name") 30 | } 31 | commandRegistry[entry] = cmd 32 | return nil 33 | } 34 | 35 | func GetCommand(name string) Command { 36 | cmd, found := commandRegistry[name] 37 | if !found { 38 | return nil 39 | } 40 | return cmd 41 | } 42 | 43 | type hiddenCommand interface { 44 | Hidden() bool 45 | } 46 | 47 | func PrintUsage() { 48 | for name, cmd := range commandRegistry { 49 | if _, ok := cmd.(hiddenCommand); ok { 50 | continue 51 | } 52 | fmt.Println(" ", name, "\t\t\t", cmd.Description()) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /infra/control/control.go: -------------------------------------------------------------------------------- 1 | package control 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /infra/control/errors.generated.go: -------------------------------------------------------------------------------- 1 | package control 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/control/uuid.go: -------------------------------------------------------------------------------- 1 | package control 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/uuid" 8 | ) 9 | 10 | type UUIDCommand struct{} 11 | 12 | func (c *UUIDCommand) Name() string { 13 | return "uuid" 14 | } 15 | 16 | func (c *UUIDCommand) Description() Description { 17 | return Description{ 18 | Short: "Generate new UUID", 19 | Usage: []string{"v2ctl uuid"}, 20 | } 21 | } 22 | 23 | func (c *UUIDCommand) Execute([]string) error { 24 | u := uuid.New() 25 | fmt.Println(u.String()) 26 | return nil 27 | } 28 | 29 | func init() { 30 | common.Must(RegisterCommand(&UUIDCommand{})) 31 | } 32 | -------------------------------------------------------------------------------- /main/confloader/confloader.go: -------------------------------------------------------------------------------- 1 | package confloader 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | 5 | import ( 6 | "io" 7 | "os" 8 | ) 9 | 10 | type ( 11 | configFileLoader func(string) (io.Reader, error) 12 | extconfigLoader func([]string, io.Reader) (io.Reader, error) 13 | ) 14 | 15 | var ( 16 | EffectiveConfigFileLoader configFileLoader 17 | EffectiveExtConfigLoader extconfigLoader 18 | ) 19 | 20 | // LoadConfig reads from a path/url/stdin 21 | // actual work is in external module 22 | func LoadConfig(file string) (io.Reader, error) { 23 | if EffectiveConfigFileLoader == nil { 24 | newError("external config module not loaded, reading from stdin").AtInfo().WriteToLog() 25 | return os.Stdin, nil 26 | } 27 | return EffectiveConfigFileLoader(file) 28 | } 29 | 30 | // LoadExtConfig calls v2ctl to handle multiple config 31 | // the actual work also in external module 32 | func LoadExtConfig(files []string, reader io.Reader) (io.Reader, error) { 33 | if EffectiveExtConfigLoader == nil { 34 | return nil, newError("external config module not loaded").AtError() 35 | } 36 | 37 | return EffectiveExtConfigLoader(files, reader) 38 | } 39 | -------------------------------------------------------------------------------- /main/confloader/errors.generated.go: -------------------------------------------------------------------------------- 1 | package confloader 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/jsonem/errors.generated.go: -------------------------------------------------------------------------------- 1 | package jsonem 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | //go:build coveragemain 2 | // +build coveragemain 3 | 4 | package main 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func TestRunMainForCoverage(t *testing.T) { 11 | main() 12 | } 13 | -------------------------------------------------------------------------------- /mocks.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | //go:generate env GOBIN=$PWD go install -v github.com/golang/mock/mockgen@latest 4 | //go:generate ./mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer 5 | //go:generate ./mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler github.com/Shadowsocks-NET/v2ray-go/v4/common/log Handler 6 | //go:generate ./mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory github.com/Shadowsocks-NET/v2ray-go/v4/common/mux ClientWorkerFactory 7 | //go:generate ./mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient github.com/Shadowsocks-NET/v2ray-go/v4/features/dns Client 8 | //go:generate ./mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector github.com/Shadowsocks-NET/v2ray-go/v4/features/outbound Manager,HandlerSelector 9 | //go:generate ./mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound github.com/Shadowsocks-NET/v2ray-go/v4/proxy Inbound,Outbound 10 | -------------------------------------------------------------------------------- /proto.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | //go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest 4 | //go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 5 | //go:generate go run ./infra/vprotogen/ 6 | -------------------------------------------------------------------------------- /proxy/blackhole/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.blackhole; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Blackhole"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/blackhole"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 10 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 | defer response.Body.Close() 23 | 24 | if response.StatusCode != 403 { 25 | t.Error("expected status code 403, but got ", response.StatusCode) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /proxy/blackhole/errors.generated.go: -------------------------------------------------------------------------------- 1 | package blackhole 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.proxy.dns; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Dns"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/dns"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.common.net.Endpoint server = 1; 15 | } 16 | -------------------------------------------------------------------------------- /proxy/dns/errors.generated.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.proxy.dokodemo; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Dokodemo"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/dokodemo"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.common.net.IPOrDomain address = 1; 14 | uint32 port = 2; 15 | 16 | // List of networks that the Dokodemo accepts. 17 | // Deprecated. Use networks. 18 | v2ray.core.common.net.NetworkList network_list = 3 [deprecated = true]; 19 | // List of networks that the Dokodemo accepts. 20 | repeated v2ray.core.common.net.Network networks = 7; 21 | 22 | bool follow_redirect = 5; 23 | uint32 user_level = 6; 24 | } 25 | -------------------------------------------------------------------------------- /proxy/dokodemo/errors.generated.go: -------------------------------------------------------------------------------- 1 | package dokodemo 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/freedom/config.go: -------------------------------------------------------------------------------- 1 | package freedom 2 | -------------------------------------------------------------------------------- /proxy/freedom/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.freedom; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Freedom"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/freedom"; 6 | option java_package = "com.v2ray.core.proxy.freedom"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | 11 | message DestinationOverride { 12 | v2ray.core.common.protocol.ServerEndpoint server = 1; 13 | } 14 | 15 | message Config { 16 | DestinationOverride destination_override = 3; 17 | uint32 user_level = 4; 18 | } 19 | -------------------------------------------------------------------------------- /proxy/freedom/errors.generated.go: -------------------------------------------------------------------------------- 1 | package freedom 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.proxy.http; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Http"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/http"; 6 | option java_package = "com.v2ray.core.proxy.http"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | 11 | message Account { 12 | string username = 1; 13 | string password = 2; 14 | } 15 | 16 | // Config for HTTP proxy server. 17 | message ServerConfig { 18 | map accounts = 2; 19 | bool allow_transparent = 3; 20 | uint32 user_level = 4; 21 | } 22 | 23 | // ClientConfig is the protobuf config for HTTP proxy client. 24 | message ClientConfig { 25 | // Sever is a list of HTTP server addresses. 26 | repeated v2ray.core.common.protocol.ServerEndpoint server = 1; 27 | } 28 | -------------------------------------------------------------------------------- /proxy/http/errors.generated.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /proxy/loopback/config.go: -------------------------------------------------------------------------------- 1 | package loopback 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /proxy/loopback/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.loopback; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Loopback"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/loopback"; 6 | option java_package = "com.v2ray.core.proxy.loopback"; 7 | option java_multiple_files = true; 8 | 9 | message Config { 10 | string inbound_tag = 1; 11 | } 12 | -------------------------------------------------------------------------------- /proxy/loopback/errors.generated.go: -------------------------------------------------------------------------------- 1 | package loopback 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.shadowsocks; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Shadowsocks"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/shadowsocks"; 6 | option java_package = "com.v2ray.core.proxy.shadowsocks"; 7 | option java_multiple_files = true; 8 | 9 | import "common/net/network.proto"; 10 | import "common/protocol/user.proto"; 11 | import "common/protocol/server_spec.proto"; 12 | 13 | message Account { 14 | string password = 1; 15 | CipherType cipher_type = 2; 16 | 17 | bool iv_check = 3; 18 | } 19 | 20 | enum CipherType { 21 | UNKNOWN = 0; 22 | AES_128_GCM = 1; 23 | AES_256_GCM = 2; 24 | CHACHA20_POLY1305 = 3; 25 | NONE = 4; 26 | } 27 | 28 | message ServerConfig { 29 | v2ray.core.common.protocol.User user = 2; 30 | repeated v2ray.core.common.net.Network network = 3; 31 | } 32 | 33 | message ClientConfig { 34 | repeated v2ray.core.common.protocol.ServerEndpoint server = 1; 35 | } 36 | -------------------------------------------------------------------------------- /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/Shadowsocks-NET/v2ray-go/v4/common" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 V2Ray's term. 4 | // 5 | // R.I.P Shadowsocks 6 | package shadowsocks 7 | 8 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 9 | -------------------------------------------------------------------------------- /proxy/socks/config.go: -------------------------------------------------------------------------------- 1 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package socks 5 | 6 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol" 7 | 8 | func (a *Account) Equals(another protocol.Account) bool { 9 | if account, ok := another.(*Account); ok { 10 | return a.Username == account.Username 11 | } 12 | return false 13 | } 14 | 15 | func (a *Account) AsAccount() (protocol.Account, error) { 16 | return a, nil 17 | } 18 | 19 | func (c *ServerConfig) HasAccount(username, password string) bool { 20 | if c.Accounts == nil { 21 | return false 22 | } 23 | storedPassed, found := c.Accounts[username] 24 | if !found { 25 | return false 26 | } 27 | return storedPassed == password 28 | } 29 | -------------------------------------------------------------------------------- /proxy/socks/errors.generated.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 5 | -------------------------------------------------------------------------------- /proxy/trojan/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.trojan; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Trojan"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/trojan"; 6 | option java_package = "com.v2ray.core.proxy.trojan"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/user.proto"; 10 | import "common/protocol/server_spec.proto"; 11 | 12 | message Account { 13 | string password = 1; 14 | } 15 | 16 | message Fallback { 17 | string alpn = 1; 18 | string path = 2; 19 | string type = 3; 20 | string dest = 4; 21 | uint64 xver = 5; 22 | } 23 | 24 | message ClientConfig { 25 | repeated v2ray.core.common.protocol.ServerEndpoint server = 1; 26 | } 27 | 28 | message ServerConfig { 29 | repeated v2ray.core.common.protocol.User users = 1; 30 | repeated Fallback fallbacks = 3; 31 | } 32 | -------------------------------------------------------------------------------- /proxy/trojan/errors.generated.go: -------------------------------------------------------------------------------- 1 | package trojan 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | -------------------------------------------------------------------------------- /proxy/vmess/account.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.vmess; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Vmess"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/vmess"; 6 | option java_package = "com.v2ray.core.proxy.vmess"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/headers.proto"; 10 | 11 | message Account { 12 | // ID of the account, in the form of a UUID, e.g., 13 | // "66ad4540-b58c-4ad2-9926-ea63445a9b57". 14 | string id = 1; 15 | // Security settings. Only applies to client side. 16 | v2ray.core.common.protocol.SecurityConfig security_settings = 3; 17 | // Define tests enabled for this account 18 | string tests_enabled = 4; 19 | } 20 | -------------------------------------------------------------------------------- /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 | func KDF(key []byte, path ...string) []byte { 10 | hmacCreator := &hMacCreator{value: []byte(KDFSaltConstVMessAEADKDF)} 11 | for _, v := range path { 12 | hmacCreator = &hMacCreator{value: []byte(v), parent: hmacCreator} 13 | } 14 | hmacf := hmacCreator.Create() 15 | hmacf.Write(key) 16 | return hmacf.Sum(nil) 17 | } 18 | 19 | type hMacCreator struct { 20 | parent *hMacCreator 21 | value []byte 22 | } 23 | 24 | func (h *hMacCreator) Create() hash.Hash { 25 | if h.parent == nil { 26 | return hmac.New(sha256.New, h.value) 27 | } 28 | return hmac.New(h.parent.Create, h.value) 29 | } 30 | 31 | func KDF16(key []byte, path ...string) []byte { 32 | r := KDF(key, path...) 33 | return r[:16] 34 | } 35 | -------------------------------------------------------------------------------- /proxy/vmess/aead/kdf_test.go: -------------------------------------------------------------------------------- 1 | package aead 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestKDFValue(t *testing.T) { 12 | GeneratedKey := KDF([]byte("Demo Key for KDF Value Test"), "Demo Path for KDF Value Test", "Demo Path for KDF Value Test2", "Demo Path for KDF Value Test3") 13 | fmt.Println(hex.EncodeToString(GeneratedKey)) 14 | assert.Equal(t, "53e9d7e1bd7bd25022b71ead07d8a596efc8a845c7888652fd684b4903dc8892", hex.EncodeToString(GeneratedKey), "Should generate expected KDF Value") 15 | } 16 | -------------------------------------------------------------------------------- /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/Shadowsocks-NET/v2ray-go/v4/common" 10 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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/encoding.go: -------------------------------------------------------------------------------- 1 | package encoding 2 | 3 | import ( 4 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 5 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/protocol" 6 | ) 7 | 8 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package inbound 5 | 6 | // GetDefaultValue returns default settings of DefaultConfig. 7 | func (c *Config) GetDefaultValue() *DefaultConfig { 8 | if c.GetDefault() == nil { 9 | return &DefaultConfig{} 10 | } 11 | return c.Default 12 | } 13 | -------------------------------------------------------------------------------- /proxy/vmess/inbound/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.proxy.vmess.inbound; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Vmess.Inbound"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/vmess/inbound"; 6 | option java_package = "com.v2ray.core.proxy.vmess.inbound"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/user.proto"; 10 | 11 | message DetourConfig { 12 | string to = 1; 13 | } 14 | 15 | message DefaultConfig { 16 | uint32 level = 2; 17 | } 18 | 19 | message Config { 20 | repeated v2ray.core.common.protocol.User user = 1; 21 | DefaultConfig default = 2; 22 | DetourConfig detour = 3; 23 | bool secure_encryption_only = 4; 24 | } 25 | -------------------------------------------------------------------------------- /proxy/vmess/inbound/errors.generated.go: -------------------------------------------------------------------------------- 1 | package inbound 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.proxy.vmess.outbound; 4 | option csharp_namespace = "V2Ray.Core.Proxy.Vmess.Outbound"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/proxy/vmess/outbound"; 6 | option java_package = "com.v2ray.core.proxy.vmess.outbound"; 7 | option java_multiple_files = true; 8 | 9 | import "common/protocol/server_spec.proto"; 10 | 11 | message Config { 12 | v2ray.core.common.protocol.ServerEndpoint Server = 1; 13 | } 14 | -------------------------------------------------------------------------------- /proxy/vmess/outbound/errors.generated.go: -------------------------------------------------------------------------------- 1 | package outbound 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 9 | -------------------------------------------------------------------------------- /proxy/vmess/vmessCtxInterface.go: -------------------------------------------------------------------------------- 1 | package vmess 2 | 3 | // example 4 | const AlterID = "VMessCtxInterface_AlterID" 5 | -------------------------------------------------------------------------------- /release/config/systemd/system/v2ray.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=V2Ray Service 3 | Documentation=https://www.v2fly.org/ 4 | After=network.target nss-lookup.target 5 | 6 | [Service] 7 | User=v2ray 8 | Group=network 9 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 10 | AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 11 | NoNewPrivileges=true 12 | ExecStart=/usr/bin/v2ray -config /etc/v2ray/config.json -suppressTimestamps 13 | Restart=on-failure 14 | RestartPreventExitStatus=23 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /release/config/systemd/system/v2ray@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=V2Ray Service 3 | Documentation=https://www.v2fly.org/ 4 | After=network.target nss-lookup.target 5 | 6 | [Service] 7 | User=v2ray 8 | Group=network 9 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 10 | AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 11 | NoNewPrivileges=true 12 | ExecStart=/usr/bin/v2ray -config /etc/v2ray/%i.json -suppressTimestamps 13 | Restart=on-failure 14 | RestartPreventExitStatus=23 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /release/config/sysusers.d/v2ray.conf: -------------------------------------------------------------------------------- 1 | u v2ray - "V2Ray" 2 | -------------------------------------------------------------------------------- /release/config/tmpfiles.d/v2ray.conf: -------------------------------------------------------------------------------- 1 | d /etc/v2ray 0755 v2ray network - 2 | -------------------------------------------------------------------------------- /release/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | include /usr/share/dpkg/default.mk 4 | 5 | BUILDDIR=_build 6 | 7 | %: 8 | dh $@ --builddirectory=$(BUILDDIR) --buildsystem=golang --with=golang 9 | 10 | execute_after_dh_auto_configure: 11 | go mod vendor 12 | cp -r vendor/* _build/src 13 | 14 | override_dh_auto_clean: 15 | dh_auto_clean 16 | rm -rf vendor 17 | 18 | override_dh_auto_build: 19 | DH_GOPKG="github.com/Shadowsocks-NET/v2ray-go/v4/main" dh_auto_build -- -ldflags "-s -w" 20 | cd $(BUILDDIR); mv bin/main bin/v2ray 21 | DH_GOPKG="github.com/Shadowsocks-NET/v2ray-go/v4/infra/control/main" dh_auto_build -- -ldflags "-s -w" -tags confonly 22 | cd $(BUILDDIR); mv bin/main bin/v2ctl 23 | 24 | override_dh_auto_install: 25 | dh_auto_install -- --no-source 26 | 27 | override_dh_auto_test: 28 | -------------------------------------------------------------------------------- /release/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /release/debian/v2ray-docs.docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /release/debian/v2ray-domain-list-community.install: -------------------------------------------------------------------------------- 1 | release/config/geosite.dat usr/share/v2ray 2 | -------------------------------------------------------------------------------- /release/debian/v2ray-geoip.install: -------------------------------------------------------------------------------- 1 | release/config/geoip.dat usr/share/v2ray 2 | -------------------------------------------------------------------------------- /release/debian/v2ray.install: -------------------------------------------------------------------------------- 1 | usr/bin 2 | release/config/config.json etc/v2ray 3 | -------------------------------------------------------------------------------- /release/debian/v2ray.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=V2Ray Service 3 | Documentation=https://www.v2fly.org/ 4 | After=network.target nss-lookup.target 5 | 6 | [Service] 7 | User=nobody 8 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 9 | AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 10 | NoNewPrivileges=true 11 | ExecStart=/usr/bin/v2ray -config /etc/v2ray/config.json 12 | Restart=on-failure 13 | RestartPreventExitStatus=23 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /release/debian/v2ray@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=V2Ray Service 3 | Documentation=https://www.v2fly.org/ 4 | After=network.target nss-lookup.target 5 | 6 | [Service] 7 | User=nobody 8 | CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 9 | AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 10 | NoNewPrivileges=true 11 | ExecStart=/usr/bin/v2ray -config /etc/v2ray/%i.json 12 | Restart=on-failure 13 | RestartPreventExitStatus=23 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /release/extra/browserforwarder/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bridge 6 | 7 | 8 | See debug console for detail 9 | 10 | 11 | -------------------------------------------------------------------------------- /release/install-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This file is accessible as https://install.direct/go.sh 4 | # Original source is located at github.com/v2fly/v2ray-core/release/install-release.sh 5 | 6 | # If not specify, default meaning of return value: 7 | # 0: Success 8 | # 1: System error 9 | # 2: Application error 10 | # 3: Network error 11 | 12 | #######color code######## 13 | RED="31m" # Error message 14 | YELLOW="33m" # Warning message 15 | colorEcho(){ 16 | echo -e "\033[${1}${@:2}\033[0m" 1>& 2 17 | } 18 | 19 | colorEcho ${RED} "ERROR: This script has been DISCARDED, please switch to fhs-install-v2ray project." 20 | colorEcho ${YELLOW} "HOW TO USE: https://github.com/v2fly/fhs-install-v2ray" 21 | colorEcho ${YELLOW} "TO MIGRATE: https://github.com/v2fly/fhs-install-v2ray/wiki/Migrate-from-the-old-script-to-this" 22 | exit 255 23 | -------------------------------------------------------------------------------- /release/requestsign.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RELEASE_DATA=$(curl --data "version=${SIGN_VERSION}" --data "password=${SIGN_SERVICE_PASSWORD}" -X POST "${SIGN_SERIVCE_URL}" ) 4 | echo $RELEASE_DATA 5 | RELEASE_ID=$(echo $RELEASE_DATA| jq -r ".id") 6 | 7 | function uploadfile() { 8 | FILE=$1 9 | CTYPE=$(file -b --mime-type $FILE) 10 | 11 | sleep 1 12 | curl -H "Authorization: token ${GITHUB_TOKEN}" -H "Content-Type: ${CTYPE}" --data-binary @$FILE "https://uploads.github.com/repos/v2fly/v2ray-core/releases/${RELEASE_ID}/assets?name=$(basename $FILE)" 13 | sleep 1 14 | } 15 | 16 | function upload() { 17 | FILE=$1 18 | DGST=$1.dgst 19 | openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >> $DGST 20 | openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >> $DGST 21 | openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >> $DGST 22 | openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >> $DGST 23 | uploadfile $FILE 24 | uploadfile $DGST 25 | } 26 | 27 | curl "https://raw.githubusercontent.com/v2fly/Release/master/v2fly/${SIGN_VERSION}.Release" > Release 28 | upload Release 29 | -------------------------------------------------------------------------------- /testing/scenarios/common_coverage.go: -------------------------------------------------------------------------------- 1 | //go:build coverage 2 | // +build coverage 3 | 4 | package scenarios 5 | 6 | import ( 7 | "bytes" 8 | "os" 9 | "os/exec" 10 | 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/uuid" 12 | ) 13 | 14 | func BuildV2Ray() error { 15 | genTestBinaryPath() 16 | if _, err := os.Stat(testBinaryPath); err == nil { 17 | return nil 18 | } 19 | 20 | cmd := exec.Command("go", "test", "-tags", "coverage coveragemain", "-coverpkg", "github.com/Shadowsocks-NET/v2ray-go/v4/...", "-c", "-o", testBinaryPath, GetSourcePath()) 21 | return cmd.Run() 22 | } 23 | 24 | func RunV2RayProtobuf(config []byte) *exec.Cmd { 25 | genTestBinaryPath() 26 | 27 | covDir := os.Getenv("V2RAY_COV") 28 | os.MkdirAll(covDir, os.ModeDir) 29 | randomID := uuid.New() 30 | profile := randomID.String() + ".out" 31 | proc := exec.Command(testBinaryPath, "-config=stdin:", "-format=pb", "-test.run", "TestRunMainForCoverage", "-test.coverprofile", profile, "-test.outputdir", covDir) 32 | proc.Stdin = bytes.NewBuffer(config) 33 | proc.Stderr = os.Stderr 34 | proc.Stdout = os.Stdout 35 | 36 | return proc 37 | } 38 | -------------------------------------------------------------------------------- /testing/scenarios/common_regular.go: -------------------------------------------------------------------------------- 1 | //go:build !coverage 2 | // +build !coverage 3 | 4 | package scenarios 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "os" 10 | "os/exec" 11 | ) 12 | 13 | func BuildV2Ray() error { 14 | genTestBinaryPath() 15 | if _, err := os.Stat(testBinaryPath); err == nil { 16 | return nil 17 | } 18 | 19 | fmt.Printf("Building V2Ray into path (%s)\n", testBinaryPath) 20 | cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath()) 21 | return cmd.Run() 22 | } 23 | 24 | func RunV2RayProtobuf(config []byte) *exec.Cmd { 25 | genTestBinaryPath() 26 | proc := exec.Command(testBinaryPath, "-config=stdin:", "-format=pb") 27 | proc.Stdin = bytes.NewBuffer(config) 28 | proc.Stderr = os.Stderr 29 | proc.Stdout = os.Stdout 30 | 31 | return proc 32 | } 33 | -------------------------------------------------------------------------------- /testing/servers/http/http.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 4 | 5 | // PickPort returns an unused TCP port of the system. 6 | func PickPort() net.Port { 7 | listener := pickPort() 8 | defer listener.Close() 9 | 10 | addr := listener.Addr().(*net.TCPAddr) 11 | return net.Port(addr.Port) 12 | } 13 | 14 | func pickPort() net.Listener { 15 | listener, err := net.Listen("tcp4", "127.0.0.1:0") 16 | if err != nil { 17 | listener = pickPort() 18 | } 19 | return listener 20 | } 21 | -------------------------------------------------------------------------------- /testing/servers/udp/port.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 4 | 5 | // PickPort returns an unused UDP port of the system. 6 | func PickPort() net.Port { 7 | conn := pickPort() 8 | defer conn.Close() 9 | 10 | addr := conn.LocalAddr().(*net.UDPAddr) 11 | return net.Port(addr.Port) 12 | } 13 | 14 | func pickPort() *net.UDPConn { 15 | conn, err := net.ListenUDP("udp4", &net.UDPAddr{ 16 | IP: net.LocalHostIP.IP(), 17 | Port: 0, 18 | }) 19 | if err != nil { 20 | conn = pickPort() 21 | } 22 | return conn 23 | } 24 | -------------------------------------------------------------------------------- /transport/config.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.transport; 4 | option csharp_namespace = "V2Ray.Core.Transport"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport"; 6 | option java_package = "com.v2ray.core.transport"; 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 V2Ray. Deprecated. Use each settings in StreamConfig. 13 | message Config { 14 | option deprecated = true; 15 | repeated v2ray.core.transport.internet.TransportConfig transport_settings = 1; 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/connection.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/testing/servers/tcp" 12 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package domainsocket 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 10 | ) 11 | 12 | const ( 13 | protocolName = "domainsocket" 14 | sizeofSunPath = 108 15 | ) 16 | 17 | func (c *Config) GetUnixAddr() (*net.UnixAddr, error) { 18 | path := c.Path 19 | if path == "" { 20 | return nil, newError("empty domain socket path") 21 | } 22 | if c.Abstract && path[0] != '@' { 23 | path = "@" + path 24 | } 25 | if c.Abstract && c.Padding { 26 | raw := []byte(path) 27 | addr := make([]byte, sizeofSunPath) 28 | copy(addr, raw) 29 | path = string(addr) 30 | } 31 | return &net.UnixAddr{ 32 | Name: path, 33 | Net: "unix", 34 | }, nil 35 | } 36 | 37 | func init() { 38 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 39 | return new(Config) 40 | })) 41 | } 42 | -------------------------------------------------------------------------------- /transport/internet/domainsocket/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.transport.internet.domainsocket; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.DomainSocket"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/domainsocket"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /transport/internet/domainsocket/errors.generated.go: -------------------------------------------------------------------------------- 1 | package domainsocket 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !windows 2 | // +build !windows 3 | 4 | package internet 5 | 6 | import ( 7 | "os" 8 | 9 | "golang.org/x/sys/unix" 10 | ) 11 | 12 | // Acquire lock 13 | func (fl *FileLocker) Acquire() error { 14 | f, err := os.Create(fl.path) 15 | if err != nil { 16 | return err 17 | } 18 | if err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil { 19 | f.Close() 20 | return newError("failed to lock file: ", fl.path).Base(err) 21 | } 22 | fl.file = f 23 | return nil 24 | } 25 | 26 | // Release lock 27 | func (fl *FileLocker) Release() { 28 | if err := unix.Flock(int(fl.file.Fd()), unix.LOCK_UN); err != nil { 29 | newError("failed to unlock file: ", fl.path).Base(err).WriteToLog() 30 | } 31 | if err := fl.file.Close(); err != nil { 32 | newError("failed to close file: ", fl.path).Base(err).WriteToLog() 33 | } 34 | if err := os.Remove(fl.path); err != nil { 35 | newError("failed to remove file: ", fl.path).Base(err).WriteToLog() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /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/Shadowsocks-NET/v2ray-go/v4/common" 5 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 6 | ) 7 | 8 | const protocolName = "gun" 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 | package v2ray.core.transport.internet.grpc.encoding; 3 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/grpc"; 4 | 5 | message Config { 6 | string host = 1; 7 | string service_name = 2; 8 | } -------------------------------------------------------------------------------- /transport/internet/grpc/encoding/encoding.go: -------------------------------------------------------------------------------- 1 | package encoding 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /transport/internet/grpc/encoding/errors.generated.go: -------------------------------------------------------------------------------- 1 | package encoding 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | package v2ray.core.transport.internet.grpc.encoding; 3 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/grpc/encoding"; 4 | 5 | message Hunk { 6 | bytes data = 1; 7 | } 8 | 9 | service GunService { 10 | rpc Tun (stream Hunk) returns (stream Hunk); 11 | } 12 | -------------------------------------------------------------------------------- /transport/internet/grpc/errors.generated.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package grpc 5 | 6 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 7 | -------------------------------------------------------------------------------- /transport/internet/header.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | // required to use go:linkname 8 | _ "unsafe" 9 | ) 10 | 11 | //go:linkname readRequest net/http.readRequest 12 | func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *http.Request, err error) 13 | -------------------------------------------------------------------------------- /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 v2ray.core.transport.internet.headers.noop; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Headers.Noop"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/headers/noop"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 8 | ) 9 | 10 | type Header struct{} 11 | 12 | func (Header) Size() int32 { 13 | return 0 14 | } 15 | 16 | // Serialize implements PacketHeader. 17 | func (Header) Serialize([]byte) {} 18 | 19 | func NewHeader(context.Context, interface{}) (interface{}, error) { 20 | return Header{}, nil 21 | } 22 | 23 | type ConnectionHeader struct{} 24 | 25 | func (ConnectionHeader) Client(conn net.Conn) net.Conn { 26 | return conn 27 | } 28 | 29 | func (ConnectionHeader) Server(conn net.Conn) net.Conn { 30 | return conn 31 | } 32 | 33 | func NewConnectionHeader(context.Context, interface{}) (interface{}, error) { 34 | return ConnectionHeader{}, nil 35 | } 36 | 37 | func init() { 38 | common.Must(common.RegisterConfig((*Config)(nil), NewHeader)) 39 | common.Must(common.RegisterConfig((*ConnectionConfig)(nil), NewConnectionHeader)) 40 | } 41 | -------------------------------------------------------------------------------- /transport/internet/headers/srtp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.transport.internet.headers.srtp; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Headers.Srtp"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/headers/srtp"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.transport.internet.headers.tls; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Headers.Tls"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/headers/tls"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.transport.internet.headers.utp; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Headers.Utp"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/headers/utp"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.transport.internet.headers.wechat; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Headers.Wechat"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/headers/wechat"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.transport.internet.headers.wireguard; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Headers.Wireguard"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/headers/wireguard"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package http 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/dice" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 10 | ) 11 | 12 | const protocolName = "http" 13 | 14 | func (c *Config) getHosts() []string { 15 | if len(c.Host) == 0 { 16 | return []string{"www.example.com"} 17 | } 18 | return c.Host 19 | } 20 | 21 | func (c *Config) isValidHost(host string) bool { 22 | hosts := c.getHosts() 23 | for _, h := range hosts { 24 | if h == host { 25 | return true 26 | } 27 | } 28 | return false 29 | } 30 | 31 | func (c *Config) getRandomHost() string { 32 | hosts := c.getHosts() 33 | return hosts[dice.Roll(len(hosts))] 34 | } 35 | 36 | func (c *Config) getNormalizedPath() string { 37 | if c.Path == "" { 38 | return "/" 39 | } 40 | if c.Path[0] != '/' { 41 | return "/" + c.Path 42 | } 43 | return c.Path 44 | } 45 | 46 | func init() { 47 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 48 | return new(Config) 49 | })) 50 | } 51 | -------------------------------------------------------------------------------- /transport/internet/http/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.transport.internet.http; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Http"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/http"; 6 | option java_package = "com.v2ray.core.transport.internet.http"; 7 | option java_multiple_files = true; 8 | 9 | import "transport/internet/headers/http/config.proto"; 10 | 11 | message Config { 12 | repeated string host = 1; 13 | string path = 2; 14 | string method = 3; 15 | repeated v2ray.core.transport.internet.headers.http.Header header = 4; 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/http/errors.generated.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /transport/internet/internet.go: -------------------------------------------------------------------------------- 1 | package internet 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/buf" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common" 9 | . "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 9 | -------------------------------------------------------------------------------- /transport/internet/kcp/xor.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 2 | // +build !amd64 3 | 4 | package kcp 5 | 6 | // xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len 7 | func xorfwd(x []byte) { 8 | for i := 4; i < len(x); i++ { 9 | x[i] ^= x[i-4] 10 | } 11 | } 12 | 13 | // xorbkd performs XOR backwords in words, x[i] ^= x[i-4], i from len to 0 14 | func xorbkd(x []byte) { 15 | for i := len(x) - 1; i >= 4; i-- { 16 | x[i] ^= x[i-4] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /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 v2ray.core.transport.internet.quic; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Quic"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/quic"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.common.protocol.SecurityConfig security = 2; 15 | v2ray.core.common.serial.TypedMessage header = 3; 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/quic/errors.generated.go: -------------------------------------------------------------------------------- 1 | package quic 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package quic 5 | 6 | import ( 7 | "sync" 8 | 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/bytespool" 10 | ) 11 | 12 | var pool *sync.Pool 13 | 14 | func init() { 15 | pool = bytespool.GetPool(2048) 16 | } 17 | 18 | func getBuffer() []byte { 19 | return pool.Get().([]byte) 20 | } 21 | 22 | func putBuffer(p []byte) { 23 | pool.Put(p) // nolint: staticcheck 24 | } 25 | -------------------------------------------------------------------------------- /transport/internet/quic/quic.go: -------------------------------------------------------------------------------- 1 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package quic 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 9 | ) 10 | 11 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 12 | 13 | // Here is some modification needs to be done before update quic vendor. 14 | // * use bytespool in buffer_pool.go 15 | // * set MaxReceivePacketSize to 1452 - 32 (16 bytes auth, 16 bytes head) 16 | // 17 | // 18 | 19 | const ( 20 | protocolName = "quic" 21 | internalDomain = "quic.internal.v2fly.org" 22 | ) 23 | 24 | func init() { 25 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 26 | return new(Config) 27 | })) 28 | } 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /transport/internet/sockopt_other.go: -------------------------------------------------------------------------------- 1 | //go:build js || dragonfly || netbsd || openbsd || solaris 2 | // +build js dragonfly netbsd openbsd solaris 3 | 4 | package internet 5 | 6 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | 8 | func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig, dest net.Destination) error { 9 | return nil 10 | } 11 | 12 | func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { 13 | return nil 14 | } 15 | 16 | func bindAddr(fd uintptr, ip []byte, port uint32) error { 17 | return nil 18 | } 19 | 20 | func setReuseAddr(fd uintptr) error { 21 | return nil 22 | } 23 | 24 | func setReusePort(fd uintptr) error { 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /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 | 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/buf" 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/testing/servers/tcp" 12 | . "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 13 | ) 14 | 15 | func TestTCPFastOpen(t *testing.T) { 16 | tcpServer := tcp.Server{ 17 | MsgProcessor: func(b []byte) []byte { 18 | return b 19 | }, 20 | } 21 | dest, err := tcpServer.StartContext(context.Background(), &SocketConfig{Tfo: SocketConfig_Enable}) 22 | common.Must(err) 23 | defer tcpServer.Close() 24 | 25 | ctx := context.Background() 26 | dialer := DefaultSystemDialer{} 27 | conn, err := dialer.Dial(ctx, nil, dest, &SocketConfig{ 28 | Tfo: SocketConfig_Enable, 29 | }) 30 | common.Must(err) 31 | defer conn.Close() 32 | 33 | _, err = conn.Write([]byte("abcd")) 34 | common.Must(err) 35 | 36 | b := buf.New() 37 | common.Must2(b.ReadFrom(conn)) 38 | if r := cmp.Diff(b.Bytes(), []byte("abcd")); r != "" { 39 | t.Fatal(r) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /transport/internet/system_dialer_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | package internet 5 | 6 | import "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | 8 | func newUDPConnWrapper(conn *net.UDPConn, destAddr *net.UDPAddr, addressFamily net.AddressFamily, sockopt *SocketConfig) (*udpConnWrapper, error) { 9 | return &udpConnWrapper{ 10 | UDPConn: conn, 11 | da: destAddr, 12 | }, nil 13 | } 14 | 15 | func (sockopt *SocketConfig) getBindInterfaceIP46() (bindInterfaceIP4, bindInterfaceIP6 []byte) { 16 | bindInterfaceIP4 = make([]byte, 4) 17 | bindInterfaceIP6 = make([]byte, 16) 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /transport/internet/system_dns_android.go: -------------------------------------------------------------------------------- 1 | //go:build android 2 | // +build android 3 | 4 | package internet 5 | 6 | import ( 7 | "context" 8 | "net" 9 | ) 10 | 11 | const SystemDNS = "8.8.8.8:53" 12 | 13 | /* DNSResolverFunc 14 | This is a temporary API and is subject to removal at any time. 15 | */ 16 | type DNSResolverFunc func() *net.Resolver 17 | 18 | /* NewDNSResolver 19 | This is a temporary API and is subject to removal at any time. 20 | */ 21 | var NewDNSResolver DNSResolverFunc = func() *net.Resolver { 22 | return &net.Resolver{ 23 | PreferGo: true, 24 | Dial: func(ctx context.Context, network, _ string) (net.Conn, error) { 25 | var dialer net.Dialer 26 | return dialer.DialContext(ctx, network, SystemDNS) 27 | }, 28 | } 29 | } 30 | 31 | func init() { 32 | net.DefaultResolver = NewDNSResolver() 33 | } 34 | -------------------------------------------------------------------------------- /transport/internet/system_dns_android_test.go: -------------------------------------------------------------------------------- 1 | //go:build android 2 | // +build android 3 | 4 | package internet 5 | 6 | import ( 7 | "context" 8 | "testing" 9 | ) 10 | 11 | func TestDNSResolver(t *testing.T) { 12 | resolver := NewDNSResolver() 13 | if ips, err := resolver.LookupIP(context.Background(), "ip", "www.google.com"); err != nil { 14 | t.Errorf("failed to lookupIP, %v, %v", ips, err) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /transport/internet/system_listener_test.go: -------------------------------------------------------------------------------- 1 | package internet_test 2 | 3 | import ( 4 | "context" 5 | "net" 6 | "testing" 7 | 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/tagged/tagged.go: -------------------------------------------------------------------------------- 1 | package tagged 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 7 | ) 8 | 9 | type DialFunc func(ctx context.Context, dest net.Destination, tag string) (net.Conn, error) 10 | 11 | var Dialer DialFunc 12 | -------------------------------------------------------------------------------- /transport/internet/tagged/taggedimpl/errors.generated.go: -------------------------------------------------------------------------------- 1 | package taggedimpl 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/tagged/taggedimpl/taggedimpl.go: -------------------------------------------------------------------------------- 1 | package taggedimpl 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /transport/internet/tcp/config.go: -------------------------------------------------------------------------------- 1 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package tcp 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 9 | ) 10 | 11 | const protocolName = "tcp" 12 | 13 | func init() { 14 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 15 | return new(Config) 16 | })) 17 | } 18 | -------------------------------------------------------------------------------- /transport/internet/tcp/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.transport.internet.tcp; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Tcp"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/tcp"; 6 | option java_package = "com.v2ray.core.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 | v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build freebsd && !confonly 2 | // +build freebsd,!confonly 3 | 4 | package tcp 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 9 | ) 10 | 11 | // GetOriginalDestination from tcp conn 12 | func GetOriginalDestination(conn internet.Connection) (net.Destination, error) { 13 | la := conn.LocalAddr() 14 | ra := conn.RemoteAddr() 15 | ip, port, err := internet.OriginalDst(la, ra) 16 | if err != nil { 17 | return net.Destination{}, newError("failed to get destination").Base(err) 18 | } 19 | dest := net.TCPDestination(net.IPAddress(ip), net.Port(port)) 20 | if !dest.IsValid() { 21 | return net.Destination{}, newError("failed to parse destination.") 22 | } 23 | return dest, nil 24 | } 25 | -------------------------------------------------------------------------------- /transport/internet/tcp/sockopt_linux_test.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package tcp_test 5 | 6 | import ( 7 | "context" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 12 | "github.com/Shadowsocks-NET/v2ray-go/v4/testing/servers/tcp" 13 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 14 | . "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/tcp" 15 | ) 16 | 17 | func TestGetOriginalDestination(t *testing.T) { 18 | tcpServer := tcp.Server{} 19 | dest, err := tcpServer.Start() 20 | common.Must(err) 21 | defer tcpServer.Close() 22 | 23 | config, err := internet.ToMemoryStreamConfig(nil) 24 | common.Must(err) 25 | conn, err := Dial(context.Background(), dest, config) 26 | common.Must(err) 27 | defer conn.Close() 28 | 29 | originalDest, err := GetOriginalDestination(conn) 30 | if !(dest == originalDest || strings.Contains(err.Error(), "failed to call getsockopt")) { 31 | t.Error("unexpected state") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /transport/internet/tcp/sockopt_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !freebsd && !confonly 2 | // +build !linux,!freebsd,!confonly 3 | 4 | package tcp 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 9 | ) 10 | 11 | func GetOriginalDestination(conn internet.Connection) (net.Destination, error) { 12 | return net.Destination{}, nil 13 | } 14 | -------------------------------------------------------------------------------- /transport/internet/tcp/tcp.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | -------------------------------------------------------------------------------- /transport/internet/tls/config_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows && !confonly 2 | // +build windows,!confonly 3 | 4 | package tls 5 | 6 | import "crypto/x509" 7 | 8 | func (c *Config) getCertPool() (*x509.CertPool, error) { 9 | if c.DisableSystemRoot { 10 | return c.loadSelfCertPool() 11 | } 12 | 13 | return nil, nil 14 | } 15 | -------------------------------------------------------------------------------- /transport/internet/tls/errors.generated.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/tls/pin.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/base64" 6 | "encoding/pem" 7 | ) 8 | 9 | func CalculatePEMCertChainSHA256Hash(certContent []byte) string { 10 | var certChain [][]byte 11 | for { 12 | block, remain := pem.Decode(certContent) 13 | if block == nil { 14 | break 15 | } 16 | certChain = append(certChain, block.Bytes) 17 | certContent = remain 18 | } 19 | certChainHash := GenerateCertChainHash(certChain) 20 | certChainHashB64 := base64.StdEncoding.EncodeToString(certChainHash) 21 | return certChainHashB64 22 | } 23 | 24 | func GenerateCertChainHash(rawCerts [][]byte) []byte { 25 | var hashValue []byte 26 | for _, certValue := range rawCerts { 27 | out := sha256.Sum256(certValue) 28 | if hashValue == nil { 29 | hashValue = out[:] 30 | } else { 31 | newHashValue := sha256.Sum256(append(hashValue, out[:]...)) 32 | hashValue = newHashValue[:] 33 | } 34 | } 35 | return hashValue 36 | } 37 | -------------------------------------------------------------------------------- /transport/internet/udp/config.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 5 | "github.com/Shadowsocks-NET/v2ray-go/v4/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 v2ray.core.transport.internet.udp; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Udp"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/udp"; 6 | option java_package = "com.v2ray.core.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/Shadowsocks-NET/v2ray-go/v4/common" 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 8 | "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | //go:build freebsd 2 | // +build freebsd 3 | 4 | package udp 5 | 6 | import ( 7 | "bytes" 8 | "encoding/gob" 9 | "io" 10 | 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 12 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 13 | ) 14 | 15 | // RetrieveOriginalDest from stored laddr, caddr 16 | func RetrieveOriginalDest(oob []byte) net.Destination { 17 | dec := gob.NewDecoder(bytes.NewBuffer(oob)) 18 | var la, ra net.UDPAddr 19 | dec.Decode(&la) 20 | dec.Decode(&ra) 21 | ip, port, err := internet.OriginalDst(&la, &ra) 22 | if err != nil { 23 | return net.Destination{} 24 | } 25 | return net.UDPDestination(net.IPAddress(ip), net.Port(port)) 26 | } 27 | 28 | // ReadUDPMsg stores laddr, caddr for later use 29 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) { 30 | nBytes, addr, err := conn.ReadFromUDP(payload) 31 | var buf bytes.Buffer 32 | enc := gob.NewEncoder(&buf) 33 | enc.Encode(conn.LocalAddr().(*net.UDPAddr)) 34 | enc.Encode(addr) 35 | var reader io.Reader = &buf 36 | noob, _ := reader.Read(oob) 37 | return nBytes, noob, 0, addr, err 38 | } 39 | -------------------------------------------------------------------------------- /transport/internet/udp/hub_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package udp 5 | 6 | import ( 7 | "syscall" 8 | 9 | "golang.org/x/sys/unix" 10 | 11 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 12 | ) 13 | 14 | func RetrieveOriginalDest(oob []byte) net.Destination { 15 | msgs, err := syscall.ParseSocketControlMessage(oob) 16 | if err != nil { 17 | return net.Destination{} 18 | } 19 | for _, msg := range msgs { 20 | if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR { 21 | ip := net.IPAddress(msg.Data[4:8]) 22 | port := net.PortFromBytes(msg.Data[2:4]) 23 | return net.UDPDestination(ip, port) 24 | } else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == unix.IPV6_RECVORIGDSTADDR { 25 | ip := net.IPAddress(msg.Data[8:24]) 26 | port := net.PortFromBytes(msg.Data[2:4]) 27 | return net.UDPDestination(ip, port) 28 | } 29 | } 30 | return net.Destination{} 31 | } 32 | 33 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) { 34 | return conn.ReadMsgUDP(payload, oob) 35 | } 36 | -------------------------------------------------------------------------------- /transport/internet/udp/hub_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !freebsd 2 | // +build !linux,!freebsd 3 | 4 | package udp 5 | 6 | import ( 7 | "github.com/Shadowsocks-NET/v2ray-go/v4/common/net" 8 | ) 9 | 10 | func RetrieveOriginalDest(oob []byte) net.Destination { 11 | return net.Destination{} 12 | } 13 | 14 | func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) { 15 | nBytes, addr, err := conn.ReadFromUDP(payload) 16 | return nBytes, 0, 0, addr, err 17 | } 18 | -------------------------------------------------------------------------------- /transport/internet/udp/udp.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | //go:generate go run github.com/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 4 | 5 | const protocolName = "udp" 6 | -------------------------------------------------------------------------------- /transport/internet/websocket/config.go: -------------------------------------------------------------------------------- 1 | //go:build !confonly 2 | // +build !confonly 3 | 4 | package websocket 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/Shadowsocks-NET/v2ray-go/v4/common" 10 | "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet" 11 | ) 12 | 13 | const protocolName = "websocket" 14 | 15 | func (c *Config) GetNormalizedPath() string { 16 | path := c.Path 17 | if path == "" { 18 | return "/" 19 | } 20 | if path[0] != '/' { 21 | return "/" + path 22 | } 23 | return path 24 | } 25 | 26 | func (c *Config) GetRequestHeader() http.Header { 27 | header := http.Header{} 28 | for _, h := range c.Header { 29 | header.Add(h.Key, h.Value) 30 | } 31 | return header 32 | } 33 | 34 | func init() { 35 | common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { 36 | return new(Config) 37 | })) 38 | } 39 | -------------------------------------------------------------------------------- /transport/internet/websocket/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package v2ray.core.transport.internet.websocket; 4 | option csharp_namespace = "V2Ray.Core.Transport.Internet.Websocket"; 5 | option go_package = "github.com/Shadowsocks-NET/v2ray-go/v4/transport/internet/websocket"; 6 | option java_package = "com.v2ray.core.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 | int32 max_early_data = 5; 25 | 26 | bool use_browser_forwarding = 6; 27 | 28 | string early_data_header_name = 7; 29 | } 30 | -------------------------------------------------------------------------------- /transport/internet/websocket/errors.generated.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/common/errors/errorgen 8 | -------------------------------------------------------------------------------- /transport/link.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import "github.com/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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/Shadowsocks-NET/v2ray-go/v4/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 | --------------------------------------------------------------------------------