diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 04eda238..e7898507 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -24,6 +24,8 @@ include_directories(src/) include_directories(libs/fptn/src/) include_directories(libs/fptn/src/fptn-protocol-lib) +include(libs/fptn/depends/cmake/CamouflageTLS.cmake) # FIXME + # disable pcap++ add_compile_definitions(FPTN_IP_ADDRESS_WITHOUT_PCAP) @@ -47,7 +49,9 @@ target_link_libraries( android log fptn::fptn - nlohmann_json::nlohmann_json) + nlohmann_json::nlohmann_json + camouflage-tls # FIXME +) target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE FPTN_VERSION=\"0.0.0\") set_target_properties( diff --git a/app/src/main/cpp/conanfile.py b/app/src/main/cpp/conanfile.py index b8e46aa7..909f04f7 100644 --- a/app/src/main/cpp/conanfile.py +++ b/app/src/main/cpp/conanfile.py @@ -23,6 +23,9 @@ class FptnLib(ConanFile): def requirements(self): self._register_local_recipe("fptn", "fptn", "0.0.0") + def build_requirements(self): + self.test_requires("gtest/1.17.0") + def layout(self): cmake_layout(self) diff --git a/app/src/main/cpp/libs/fptn b/app/src/main/cpp/libs/fptn index 4baae524..0c0ca39c 160000 --- a/app/src/main/cpp/libs/fptn +++ b/app/src/main/cpp/libs/fptn @@ -1 +1 @@ -Subproject commit 4baae5242c0292730504ce284a85ebab64a75cb8 +Subproject commit 0c0ca39cc529c8fbfe274513c9c9be1a427a465f diff --git a/app/src/main/cpp/src/https_client.cpp b/app/src/main/cpp/src/https_client.cpp index c0fbebfb..51b1b4e1 100644 --- a/app/src/main/cpp/src/https_client.cpp +++ b/app/src/main/cpp/src/https_client.cpp @@ -111,9 +111,34 @@ Java_org_fptn_vpn_services_websocket_NativeHttpsClientImpl_nativeCreate( fptn::protocol::https::CensorshipStrategy::kSni; if (censorship_strategy_name == "OBFUSCATION") { censorship_strategy = fptn::protocol::https::CensorshipStrategy::kTlsObfuscator; - } else if (censorship_strategy_name == "SNI-REALITY") { + } else if (censorship_strategy_name == "SNI-REALITY") { // deprecated censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityMode; } + /* Chrome */ + else if (censorship_strategy_name == "SNI-REALITY-CHROME-147") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeChrome147; + } else if (censorship_strategy_name == "SNI-REALITY-CHROME-146") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeChrome146; + } else if (censorship_strategy_name == "SNI-REALITY-CHROME-145") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeChrome145; + } + /* Firefox */ + else if (censorship_strategy_name == "SNI-REALITY-FIREFOX-149") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeFirefox149; + } + /* Yandex */ + else if (censorship_strategy_name == "SNI-REALITY-YANDEX-26") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeYandex26; + } else if (censorship_strategy_name == "SNI-REALITY-YANDEX-25") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeYandex25; + } else if (censorship_strategy_name == "SNI-REALITY-YANDEX-24") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeYandex24; + } + /* Safari */ + else if (censorship_strategy_name == "SNI-REALITY-SAFARI-26") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeSafari26; + } + auto* https_client = new WrapperHttpsClient(env, global_object_ref, std::move(host), port, std::move(sni), std::move(md5_fingerprint), censorship_strategy); diff --git a/app/src/main/cpp/src/websocket_client.cpp b/app/src/main/cpp/src/websocket_client.cpp index 55abc625..6e7afd6e 100644 --- a/app/src/main/cpp/src/websocket_client.cpp +++ b/app/src/main/cpp/src/websocket_client.cpp @@ -89,9 +89,33 @@ Java_org_fptn_vpn_services_websocket_NativeWebSocketClientImpl_nativeCreate( fptn::protocol::https::CensorshipStrategy::kSni; if (censorship_strategy_name == "OBFUSCATION") { censorship_strategy = fptn::protocol::https::CensorshipStrategy::kTlsObfuscator; - } else if (censorship_strategy_name == "SNI-REALITY") { + } else if (censorship_strategy_name == "SNI-REALITY") { // deprecated censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityMode; } + /* Chrome */ + else if (censorship_strategy_name == "SNI-REALITY-CHROME-147") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeChrome147; + } else if (censorship_strategy_name == "SNI-REALITY-CHROME-146") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeChrome146; + } else if (censorship_strategy_name == "SNI-REALITY-CHROME-145") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeChrome145; + } + /* Firefox */ + else if (censorship_strategy_name == "SNI-REALITY-FIREFOX-149") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeFirefox149; + } + /* Yandex */ + else if (censorship_strategy_name == "SNI-REALITY-YANDEX-26") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeYandex26; + } else if (censorship_strategy_name == "SNI-REALITY-YANDEX-25") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeYandex25; + } else if (censorship_strategy_name == "SNI-REALITY-YANDEX-24") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeYandex24; + } + /* Safari */ + else if (censorship_strategy_name == "SNI-REALITY-SAFARI-26") { + censorship_strategy = fptn::protocol::https::CensorshipStrategy::kSniRealityModeSafari26; + } jobject global_object_ref = env->NewWeakGlobalRef(thiz); auto* websocket_client = new WrapperWebsocketClient(global_object_ref, diff --git a/app/src/main/cpp/src/wrappers/wrapper_websocket_client/wrapper_websocket_client.cpp b/app/src/main/cpp/src/wrappers/wrapper_websocket_client/wrapper_websocket_client.cpp index 7e4f7414..9e59fcf1 100644 --- a/app/src/main/cpp/src/wrappers/wrapper_websocket_client/wrapper_websocket_client.cpp +++ b/app/src/main/cpp/src/wrappers/wrapper_websocket_client/wrapper_websocket_client.cpp @@ -311,9 +311,12 @@ bool WrapperWebsocketClient::Send(std::string pkt) { if (!running_) { return false; } - try { - auto ip_packet = fptn::common::network::IPPacket::Parse(std::move(pkt)); + std::vector packet_data; + packet_data.reserve(pkt.size()); + std::move(pkt.begin(), pkt.end(), std::back_inserter(packet_data)); + + auto ip_packet = fptn::common::network::IPPacket::Parse(std::move(packet_data)); if (!ip_packet) { SPDLOG_ERROR("Failed to parse IP packet in Send"); return false; diff --git a/app/src/main/java/org/fptn/vpn/enums/BypassCensorshipMethod.java b/app/src/main/java/org/fptn/vpn/enums/BypassCensorshipMethod.java index 779f699e..d230c409 100644 --- a/app/src/main/java/org/fptn/vpn/enums/BypassCensorshipMethod.java +++ b/app/src/main/java/org/fptn/vpn/enums/BypassCensorshipMethod.java @@ -1,7 +1,19 @@ package org.fptn.vpn.enums; public enum BypassCensorshipMethod { - SNI_SPOOFING, + SNI_SPOOFING, // deprecated TLS_OBFUSCATION, - SNI_REALITY + SNI_REALITY, // deprecated + /* Chrome */ + SNI_REALITY_CHROME_147, + SNI_REALITY_CHROME_146, + SNI_REALITY_CHROME_145, + /* Firefox */ + SNI_REALITY_FIREFOX_149, + /* Yandex Browser */ + SNI_REALITY_YANDEX_26, + SNI_REALITY_YANDEX_25, + SNI_REALITY_YANDEX_24, + /* Safari */ + SNI_REALITY_SAFARI_26 } diff --git a/app/src/main/java/org/fptn/vpn/services/speedtest/NativeSpeedTestTask.java b/app/src/main/java/org/fptn/vpn/services/speedtest/NativeSpeedTestTask.java index c4e0a7db..a3e08b9f 100644 --- a/app/src/main/java/org/fptn/vpn/services/speedtest/NativeSpeedTestTask.java +++ b/app/src/main/java/org/fptn/vpn/services/speedtest/NativeSpeedTestTask.java @@ -36,15 +36,12 @@ public NativeSpeedTestTask(ServerEntity serverEntity, String sniHost, BypassCens @Override public NativeSpeedTestResult call() throws PVNClientException { Instant start = Instant.now(); - Log.d(getTag(), "call() start test: " + serverEntity.getName()); NativeResponse response = nativeHttpsClient.Get(GET_FILE_PATH, TIMEOUT); if (response.code == 200) { Instant end = Instant.now(); long durationsMillis = Duration.between(start, end).toMillis(); - Log.d(getTag(), "call() end test: " + serverEntity.getName() + " duration: " + durationsMillis + " ms"); return new NativeSpeedTestResult(serverEntity, durationsMillis); } else { - Log.d(getTag(), "call() end test: " + serverEntity.getName() + " error: " + response.errorMessage); throw new PVNClientException(response.errorMessage); } } diff --git a/app/src/main/java/org/fptn/vpn/services/websocket/NativeHttpsClientImpl.java b/app/src/main/java/org/fptn/vpn/services/websocket/NativeHttpsClientImpl.java index 9e3bdc2f..2e4824d4 100644 --- a/app/src/main/java/org/fptn/vpn/services/websocket/NativeHttpsClientImpl.java +++ b/app/src/main/java/org/fptn/vpn/services/websocket/NativeHttpsClientImpl.java @@ -18,13 +18,36 @@ public NativeHttpsClientImpl(String serverIP, String md5Fingerprint, String sni, BypassCensorshipMethod censorshipStrategy) { - String censorshipStrategyName = "SNI"; + String censorshipStrategyName = "SNI-REALITY-YANDEX-25"; if (censorshipStrategy == BypassCensorshipMethod.TLS_OBFUSCATION) { censorshipStrategyName = "OBFUSCATION"; - } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY) { + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY) { // deprecated censorshipStrategyName = "SNI-REALITY"; } - + /* Chrome */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_CHROME_147) { + censorshipStrategyName = "SNI-REALITY-CHROME-147"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_CHROME_146) { + censorshipStrategyName = "SNI-REALITY-CHROME-146"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_CHROME_145) { + censorshipStrategyName = "SNI-REALITY-CHROME-145"; + } + /* Firefox */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_FIREFOX_149) { + censorshipStrategyName = "SNI-REALITY-FIREFOX-149"; + } + /* Yandex */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_YANDEX_26) { + censorshipStrategyName = "SNI-REALITY-YANDEX-26"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_YANDEX_25) { + censorshipStrategyName = "SNI-REALITY-YANDEX-25"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_YANDEX_24) { + censorshipStrategyName = "SNI-REALITY-YANDEX-24"; + } + /* Safari */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_SAFARI_26) { + censorshipStrategyName = "SNI-REALITY-SAFARI-26"; + } this.nativeHandle = nativeCreate( serverIP, serverPort, diff --git a/app/src/main/java/org/fptn/vpn/services/websocket/NativeWebSocketClientImpl.java b/app/src/main/java/org/fptn/vpn/services/websocket/NativeWebSocketClientImpl.java index 63af9e0c..6da0ea4f 100644 --- a/app/src/main/java/org/fptn/vpn/services/websocket/NativeWebSocketClientImpl.java +++ b/app/src/main/java/org/fptn/vpn/services/websocket/NativeWebSocketClientImpl.java @@ -39,16 +39,40 @@ public NativeWebSocketClientImpl( OnMessageReceivedCallback onMessageReceivedCallback, OnFailureCallback onFailureCallback, String sniHostName, - BypassCensorshipMethod censorship_strategy) throws PVNClientException { + BypassCensorshipMethod censorshipStrategy) throws PVNClientException { this.onOpenCallback = onOpenCallback; this.onMessageReceivedCallback = onMessageReceivedCallback; this.onFailureCallback = onFailureCallback; - String censorship_strategy_name = "SNI"; - if (censorship_strategy == BypassCensorshipMethod.TLS_OBFUSCATION) { - censorship_strategy_name = "OBFUSCATION"; - } else if (censorship_strategy == BypassCensorshipMethod.SNI_REALITY) { - censorship_strategy_name = "SNI-REALITY"; + String censorshipStrategyName = "SNI-REALITY-YANDEX-25"; + if (censorshipStrategy == BypassCensorshipMethod.TLS_OBFUSCATION) { + censorshipStrategyName = "OBFUSCATION"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY) { // deprecated + censorshipStrategyName = "SNI-REALITY"; + } + /* Chrome */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_CHROME_147) { + censorshipStrategyName = "SNI-REALITY-CHROME-147"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_CHROME_146) { + censorshipStrategyName = "SNI-REALITY-CHROME-146"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_CHROME_145) { + censorshipStrategyName = "SNI-REALITY-CHROME-145"; + } + /* Firefox */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_FIREFOX_149) { + censorshipStrategyName = "SNI-REALITY-FIREFOX-149"; + } + /* Yandex */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_YANDEX_26) { + censorshipStrategyName = "SNI-REALITY-YANDEX-26"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_YANDEX_25) { + censorshipStrategyName = "SNI-REALITY-YANDEX-25"; + } else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_YANDEX_24) { + censorshipStrategyName = "SNI-REALITY-YANDEX-24"; + } + /* Safari */ + else if (censorshipStrategy == BypassCensorshipMethod.SNI_REALITY_SAFARI_26) { + censorshipStrategyName = "SNI-REALITY-SAFARI-26"; } this.nativeHandle = nativeCreate( @@ -59,7 +83,7 @@ public NativeWebSocketClientImpl( sniHostName, accessToken, md5ServerFingerprint, - censorship_strategy_name + censorshipStrategyName ); this.serialNum = SERIAL_NUM.getAndIncrement(); diff --git a/app/src/main/java/org/fptn/vpn/views/bypassmethod/BypassMethodsActivity.java b/app/src/main/java/org/fptn/vpn/views/bypassmethod/BypassMethodsActivity.java index c69e0db1..770cc160 100644 --- a/app/src/main/java/org/fptn/vpn/views/bypassmethod/BypassMethodsActivity.java +++ b/app/src/main/java/org/fptn/vpn/views/bypassmethod/BypassMethodsActivity.java @@ -49,6 +49,9 @@ public class BypassMethodsActivity extends AppCompatActivity { private final String TAG = this.getClass().getSimpleName(); + + private View sniLayout; + private BypassMethodsViewModel viewModel; private ActivityResultLauncher filePickerLauncher; private AlertDialog autoSelectDialog; @@ -113,35 +116,107 @@ private void initializeVariable() { // Setup RadioGroup listener RadioGroup protocolRadioGroup = findViewById(R.id.bypass_method_radio_button_group); protocolRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { - if (checkedId == R.id.sni_spoofing_radio_button) { - Log.d(TAG, "Selected SNI spoofing"); - viewModel.setBypassMethod(BypassCensorshipMethod.SNI_SPOOFING); - } else if (checkedId == R.id.obfuscation_radio_button) { + if (checkedId == R.id.obfuscation_radio_button) { Log.d(TAG, "Selected TLS obfuscation"); viewModel.setBypassMethod(BypassCensorshipMethod.TLS_OBFUSCATION); - } else if (checkedId == R.id.sni_reality_radio_button) { - Log.d(TAG, "Selected SNI Reality"); - viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY); + } + /* Chrome */ + else if (checkedId == R.id.sni_reality_radio_button_chrome_147) { + Log.d(TAG, "Selected SNI Reality Chrome 147"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_CHROME_147); + } else if (checkedId == R.id.sni_reality_radio_button_chrome_146) { + Log.d(TAG, "Selected SNI Reality Chrome 146"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_CHROME_146); + } else if (checkedId == R.id.sni_reality_radio_button_chrome_145) { + Log.d(TAG, "Selected SNI Reality Chrome 145"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_CHROME_145); + } + /* Firefox */ + else if (checkedId == R.id.sni_reality_radio_button_firefox_149) { + Log.d(TAG, "Selected SNI Reality Firefox 149"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_FIREFOX_149); + } + /* Yandex */ + else if (checkedId == R.id.sni_reality_radio_button_yandex_26) { + Log.d(TAG, "Selected SNI Reality Yandex 26"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_YANDEX_26); + } else if (checkedId == R.id.sni_reality_radio_button_yandex_25) { + Log.d(TAG, "Selected SNI Reality Yandex 25"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_YANDEX_25); + } else if (checkedId == R.id.sni_reality_radio_button_yandex_24) { + Log.d(TAG, "Selected SNI Reality Yandex 24"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_YANDEX_24); + } + /* Safari */ + else if (checkedId == R.id.sni_reality_radio_button_safari_26) { + Log.d(TAG, "Selected SNI Reality Safari 26"); + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_SAFARI_26); + } else { + // default + viewModel.setBypassMethod(BypassCensorshipMethod.SNI_REALITY_YANDEX_25); } }); - View sniLayout = findViewById(R.id.sni_layout); - - RadioButton sniSpoofingRadioButton = findViewById(R.id.sni_spoofing_radio_button); RadioButton obfuscationRadioButton = findViewById(R.id.obfuscation_radio_button); - RadioButton sniRealityRadioButton = findViewById(R.id.sni_reality_radio_button); + + RadioButton sniRealityRadioButtonChrome147 = findViewById(R.id.sni_reality_radio_button_chrome_147); + RadioButton sniRealityRadioButtonChrome146 = findViewById(R.id.sni_reality_radio_button_chrome_146); + RadioButton sniRealityRadioButtonChrome145 = findViewById(R.id.sni_reality_radio_button_chrome_145); + + RadioButton sniRealityRadioButtonFirefox149 = findViewById(R.id.sni_reality_radio_button_firefox_149); + + RadioButton sniRealityRadioButtonYandex26 = findViewById(R.id.sni_reality_radio_button_yandex_26); + RadioButton sniRealityRadioButtonYandex25 = findViewById(R.id.sni_reality_radio_button_yandex_25); + RadioButton sniRealityRadioButtonYandex24 = findViewById(R.id.sni_reality_radio_button_yandex_24); + + RadioButton sniRealityRadioButtonSafari26 = findViewById(R.id.sni_reality_radio_button_safari_26); + viewModel.getBypassCensorshipMethodMutableLiveData().observe(this, bypassCensorshipMethod -> { switch (bypassCensorshipMethod) { - case SNI_SPOOFING: - sniSpoofingRadioButton.setChecked(true); - ViewUtils.showView(sniLayout); - break; case TLS_OBFUSCATION: obfuscationRadioButton.setChecked(true); ViewUtils.hideView(sniLayout); break; - case SNI_REALITY: - sniRealityRadioButton.setChecked(true); + case SNI_SPOOFING: // deprecated + case SNI_REALITY: // deprecated + /* Yandex */ + case SNI_REALITY_YANDEX_25: + sniRealityRadioButtonYandex25.setChecked(true); + ViewUtils.showView(sniLayout); + break; + case SNI_REALITY_YANDEX_26: + sniRealityRadioButtonYandex26.setChecked(true); + ViewUtils.showView(sniLayout); + break; + case SNI_REALITY_YANDEX_24: + sniRealityRadioButtonYandex24.setChecked(true); + ViewUtils.showView(sniLayout); + break; + /* Chrome */ + case SNI_REALITY_CHROME_147: + sniRealityRadioButtonChrome147.setChecked(true); + ViewUtils.showView(sniLayout); + break; + case SNI_REALITY_CHROME_146: + sniRealityRadioButtonChrome146.setChecked(true); + ViewUtils.showView(sniLayout); + break; + case SNI_REALITY_CHROME_145: + sniRealityRadioButtonChrome145.setChecked(true); + ViewUtils.showView(sniLayout); + break; + /* Firefox */ + case SNI_REALITY_FIREFOX_149: + sniRealityRadioButtonFirefox149.setChecked(true); + ViewUtils.showView(sniLayout); + break; + /* Safari */ + case SNI_REALITY_SAFARI_26: + sniRealityRadioButtonSafari26.setChecked(true); + ViewUtils.showView(sniLayout); + break; + default: + sniRealityRadioButtonYandex25.setChecked(true); ViewUtils.showView(sniLayout); break; } diff --git a/app/src/main/res/layout/settings_bypass_methods_layout.xml b/app/src/main/res/layout/settings_bypass_methods_layout.xml index 83c03a7f..98557766 100644 --- a/app/src/main/res/layout/settings_bypass_methods_layout.xml +++ b/app/src/main/res/layout/settings_bypass_methods_layout.xml @@ -9,7 +9,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml index 46ab87a6..a141fbdd 100644 --- a/app/src/main/res/values-fa-rIR/strings.xml +++ b/app/src/main/res/values-fa-rIR/strings.xml @@ -163,6 +163,18 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn مخفی‌سازی ترافیک (Obfuscation) جعل پیشرفتهٔ دامنه (SNI + REALITY) + (Chrome 147) جعل پیشرفتهٔ دامنه + (Chrome 146) جعل پیشرفتهٔ دامنه + (Chrome 145) جعل پیشرفتهٔ دامنه + + (Firefox 149) جعل پیشرفتهٔ دامنه + + (Yandex 26) جعل پیشرفتهٔ دامنه + Yandex 25) جعل پیشرفتهٔ دامنه + Yandex 24) جعل پیشرفتهٔ دامنه + + (Safari 26) جعل پیشرفتهٔ دامنه + نیازمند یک دامنهٔ واقعی و فعال است (در غیر این صورت ممکن است خطا رخ دهد) در حال انتخاب بهترین سرور… diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 2858d50d..416e84a9 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -160,6 +160,18 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn Маскировка трафика (обфускация) Продвинутая подмена домена (SNI + REALITY) + Подмена домена (Chrome 147) + Подмена домена (Chrome 146) + Подмена домена (Chrome 145) + + Подмена домена (Firefox 149) + + Подмена домена (Yandex 26) + Подмена домена (Yandex 25) + Подмена домена (Yandex 24) + + Подмена домена (Safari 26) + Требуется реальный существующий домен (иначе возможны ошибки) Настройки туннелирования для приложений diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 35b9d7e8..ccc3177b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -230,6 +230,19 @@ https://play.google.com/store/apps/details?id=org.fptn.vpn Traffic masking (obfuscation) Advanced domain spoofing (SNI + REALITY) + Domain spoofing (Chrome 147) + Domain spoofing (Chrome 146) + Domain spoofing (Chrome 145) + + Domain spoofing (Firefox 149) + + Domain spoofing (Yandex 26) + Domain spoofing (Yandex 25) + Domain spoofing (Yandex 24) + + Domain spoofing (Safari 26) + + Requires a real existing domain (otherwise errors may occur) Selecting the best server...