diff --git a/AndroidLibXrayLite b/AndroidLibXrayLite index 8ad3e1dd..ddcaecad 160000 --- a/AndroidLibXrayLite +++ b/AndroidLibXrayLite @@ -1 +1 @@ -Subproject commit 8ad3e1ddf165d8d67e488346b2faa9153d3e33a4 +Subproject commit ddcaecad0ae2f0816b33b8a56d1e36fce4efcae4 diff --git a/V2rayNG/app/build.gradle.kts b/V2rayNG/app/build.gradle.kts index 1624786c..c66250d9 100644 --- a/V2rayNG/app/build.gradle.kts +++ b/V2rayNG/app/build.gradle.kts @@ -12,8 +12,8 @@ android { applicationId = "com.v2ray.ang" minSdk = 21 targetSdk = 35 - versionCode = 658 - versionName = "1.10.8" + versionCode = 654 + versionName = "1.10.4" multiDexEnabled = true val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';') diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt index 09e3a9d5..9e1b7918 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt @@ -26,7 +26,6 @@ object AppConfig { const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port" const val PREF_VPN_DNS = "pref_vpn_dns" const val PREF_VPN_BYPASS_LAN = "pref_vpn_bypass_lan" - const val PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX = "pref_vpn_interface_address_config_index" const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy" const val PREF_ROUTING_RULESET = "pref_routing_ruleset" const val PREF_MUX_ENABLED = "pref_mux_enabled" @@ -56,7 +55,6 @@ object AppConfig { const val PREF_DNS_HOSTS = "pref_dns_hosts" const val PREF_DELAY_TEST_URL = "pref_delay_test_url" const val PREF_LOGLEVEL = "pref_core_loglevel" - const val PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD = "pref_outbound_domain_resolve_method" const val PREF_MODE = "pref_mode" const val PREF_IS_BOOTED = "pref_is_booted" const val PREF_CHECK_UPDATE_PRE_RELEASE = "pref_check_update_pre_release" @@ -170,9 +168,7 @@ object AppConfig { // Android Private DNS constants const val DNS_DNSPOD_DOMAIN = "dot.pub" const val DNS_ALIDNS_DOMAIN = "dns.alidns.com" - const val DNS_CLOUDFLARE_ONE_DOMAIN = "one.one.one.one" - const val DNS_CLOUDFLARE_DNS_COM_DOMAIN = "dns.cloudflare.com" - const val DNS_CLOUDFLARE_DNS_DOMAIN = "cloudflare-dns.com" + const val DNS_CLOUDFLARE_DOMAIN = "one.one.one.one" const val DNS_GOOGLE_DOMAIN = "dns.google" const val DNS_QUAD9_DOMAIN = "dns.quad9.net" const val DNS_YANDEX_DOMAIN = "common.dot.dns.yandex.net" @@ -186,16 +182,14 @@ object AppConfig { const val HEADER_TYPE_HTTP = "http" val DNS_ALIDNS_ADDRESSES = arrayListOf("223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1") - val DNS_CLOUDFLARE_ONE_ADDRESSES = arrayListOf("1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001") - val DNS_CLOUDFLARE_DNS_COM_ADDRESSES = arrayListOf("104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5") - val DNS_CLOUDFLARE_DNS_ADDRESSES = arrayListOf("104.16.248.249", "104.16.249.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9") + val DNS_CLOUDFLARE_ADDRESSES = arrayListOf("1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001") val DNS_DNSPOD_ADDRESSES = arrayListOf("1.12.12.12", "120.53.53.53") val DNS_GOOGLE_ADDRESSES = arrayListOf("8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844") val DNS_QUAD9_ADDRESSES = arrayListOf("9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9") val DNS_YANDEX_ADDRESSES = arrayListOf("77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff") //minimum list https://serverfault.com/a/304791 - val ROUTED_IP_LIST = arrayListOf( + val BYPASS_PRIVATE_IP_LIST = arrayListOf( "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/VpnInterfaceAddressConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/VpnInterfaceAddressConfig.kt deleted file mode 100644 index 6b7bc379..00000000 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/VpnInterfaceAddressConfig.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.v2ray.ang.dto - -/** - * VPN interface address configuration enum class - * Defines predefined IPv4 and IPv6 address pairs for VPN TUN interface configuration. - * Each option provides client and router addresses to establish point-to-point VPN tunnels. - */ -enum class VpnInterfaceAddressConfig( - val displayName: String, - val ipv4Client: String, - val ipv4Router: String, - val ipv6Client: String, - val ipv6Router: String -) { - OPTION_1("10.10.14.x", "10.10.14.1", "10.10.14.2", "fc00::10:10:14:1", "fc00::10:10:14:2"), - OPTION_2("10.1.0.x", "10.1.0.1", "10.1.0.2", "fc00::10:1:0:1", "fc00::10:1:0:2"), - OPTION_3("10.0.0.x", "10.0.0.1", "10.0.0.2", "fc00::10:0:0:1", "fc00::10:0:0:2"), - OPTION_4("172.31.0.x", "172.31.0.1", "172.31.0.2", "fc00::172:31:0:1", "fc00::172:31:0:2"), - OPTION_5("172.20.0.x", "172.20.0.1", "172.20.0.2", "fc00::172:20:0:1", "fc00::172:20:0:2"), - OPTION_6("172.16.0.x", "172.16.0.1", "172.16.0.2", "fc00::172:16:0:1", "fc00::172:16:0:2"), - OPTION_7("192.168.100.x", "192.168.100.1", "192.168.100.2", "fc00::192:168:100:1", "fc00::192:168:100:2"); - - companion object { - /** - * Retrieves the VPN interface address configuration based on the specified index. - * - * @param index The configuration index (0-based) corresponding to user selection - * @return The VpnInterfaceAddressConfig instance at the specified index, - * or OPTION_1 (default) if the index is out of bounds - */ - fun getConfigByIndex(index: Int): VpnInterfaceAddressConfig { - return if (index in values().indices) { - values()[index] - } else { - OPTION_1 // Default to the first configuration - } - } - } -} diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt index 73cdf958..cc9a70ff 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt @@ -4,8 +4,6 @@ import com.v2ray.ang.AppConfig import com.v2ray.ang.dto.NetworkType import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.extension.isNotNullEmpty -import com.v2ray.ang.handler.MmkvManager -import com.v2ray.ang.util.HttpUtil import com.v2ray.ang.util.Utils import java.net.URI @@ -28,7 +26,7 @@ open class FmtBase { val url = String.format( "%s@%s:%s", Utils.urlEncode(userInfo ?: ""), - Utils.getIpv6Address(HttpUtil.toIdnDomain(config.server.orEmpty())), + Utils.getIpv6Address(config.server), config.serverPort ) @@ -151,20 +149,6 @@ open class FmtBase { return dicQuery } - fun getServerAddress(profileItem: ProfileItem): String { - if (Utils.isPureIpAddress(profileItem.server.orEmpty())) { - return profileItem.server.orEmpty() - } - val domain = HttpUtil.toIdnDomain(profileItem.server.orEmpty()) - if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") != "2") { - return domain - } - //Resolve and replace domain - val resolvedIps = HttpUtil.resolveHostToIP(domain, MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6)) - if (resolvedIps.isNullOrEmpty()) { - return domain - } - return resolvedIps.first() - } + } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt index 8c641f24..73def17e 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt @@ -17,7 +17,7 @@ object HttpFmt : FmtBase() { val outboundBean = V2rayConfigManager.createInitOutbound(EConfigType.HTTP) outboundBean?.settings?.servers?.first()?.let { server -> - server.address = getServerAddress(profileItem) + server.address = profileItem.server.orEmpty() server.port = profileItem.serverPort.orEmpty().toInt() if (profileItem.username.isNotNullEmpty()) { val socksUsersBean = OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean() diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt index 87ba74f8..172716c9 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt @@ -135,7 +135,7 @@ object ShadowsocksFmt : FmtBase() { val outboundBean = V2rayConfigManager.createInitOutbound(EConfigType.SHADOWSOCKS) outboundBean?.settings?.servers?.first()?.let { server -> - server.address = getServerAddress(profileItem) + server.address = profileItem.server.orEmpty() server.port = profileItem.serverPort.orEmpty().toInt() server.password = profileItem.password server.method = profileItem.method diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt index 30bc08e4..6b727025 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt @@ -64,7 +64,7 @@ object SocksFmt : FmtBase() { val outboundBean = V2rayConfigManager.createInitOutbound(EConfigType.SOCKS) outboundBean?.settings?.servers?.first()?.let { server -> - server.address = getServerAddress(profileItem) + server.address = profileItem.server.orEmpty() server.port = profileItem.serverPort.orEmpty().toInt() if (profileItem.username.isNotNullEmpty()) { val socksUsersBean = OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean() diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt index 446ef99c..6ad0d71b 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt @@ -64,7 +64,7 @@ object TrojanFmt : FmtBase() { val outboundBean = V2rayConfigManager.createInitOutbound(EConfigType.TROJAN) outboundBean?.settings?.servers?.first()?.let { server -> - server.address = getServerAddress(profileItem) + server.address = profileItem.server.orEmpty() server.port = profileItem.serverPort.orEmpty().toInt() server.password = profileItem.password server.flow = profileItem.flow diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt index 9242f0ec..f5cf9fff 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt @@ -60,7 +60,7 @@ object VlessFmt : FmtBase() { val outboundBean = V2rayConfigManager.createInitOutbound(EConfigType.VLESS) outboundBean?.settings?.vnext?.first()?.let { vnext -> - vnext.address = getServerAddress(profileItem) + vnext.address = profileItem.server.orEmpty() vnext.port = profileItem.serverPort.orEmpty().toInt() vnext.users[0].id = profileItem.password.orEmpty() vnext.users[0].encryption = profileItem.method diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt index 4201f4dc..c733f3dc 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt @@ -172,7 +172,7 @@ object VmessFmt : FmtBase() { val outboundBean = V2rayConfigManager.createInitOutbound(EConfigType.VMESS) outboundBean?.settings?.vnext?.first()?.let { vnext -> - vnext.address = getServerAddress(profileItem) + vnext.address = profileItem.server.orEmpty() vnext.port = profileItem.serverPort.orEmpty().toInt() vnext.users[0].id = profileItem.password.orEmpty() vnext.users[0].security = profileItem.method diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt index d24ae0c2..1dcd1276 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt @@ -415,7 +415,7 @@ object AngConfigManager { if (!it.second.enabled) { return 0 } - val url = HttpUtil.toIdnUrl(it.second.url) + val url = HttpUtil.idnToASCII(it.second.url) if (!Utils.isValidUrl(url)) { return 0 } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SettingsManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SettingsManager.kt index b2e23f7f..c528aeb2 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SettingsManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SettingsManager.kt @@ -16,7 +16,6 @@ import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.RoutingType import com.v2ray.ang.dto.RulesetItem import com.v2ray.ang.dto.V2rayConfig -import com.v2ray.ang.dto.VpnInterfaceAddressConfig import com.v2ray.ang.handler.MmkvManager.decodeServerConfig import com.v2ray.ang.handler.MmkvManager.decodeServerList import com.v2ray.ang.util.JsonUtil @@ -160,7 +159,7 @@ object SettingsManager { * @return True if bypassing LAN, false otherwise. */ fun routingRulesetsBypassLan(): Boolean { - val vpnBypassLan = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_BYPASS_LAN) ?: "1" + val vpnBypassLan = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_BYPASS_LAN) ?: "0" if (vpnBypassLan == "1") { return true } else if (vpnBypassLan == "2") { @@ -357,17 +356,4 @@ object SettingsManager { "2" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) } } - - /** - * Retrieves the currently selected VPN interface address configuration. - * This method reads the user's preference for VPN interface addressing and returns - * the corresponding configuration containing IPv4 and IPv6 addresses. - * - * @return The selected VpnInterfaceAddressConfig instance, or the default configuration - * if no valid selection is found or if the stored index is invalid. - */ - fun getCurrentVpnInterfaceAddressConfig(): VpnInterfaceAddressConfig { - val selectedIndex = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX, "0")?.toInt() - return VpnInterfaceAddressConfig.getConfigByIndex(selectedIndex ?: 0) - } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/UpdateCheckerManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/UpdateCheckerManager.kt index 37b55c2e..e152002f 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/UpdateCheckerManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/UpdateCheckerManager.kt @@ -17,6 +17,7 @@ import java.io.FileOutputStream object UpdateCheckerManager { suspend fun checkForUpdate(includePreRelease: Boolean = false): CheckUpdateResult = withContext(Dispatchers.IO) { + try { val url = if (includePreRelease) { AppConfig.APP_API_URL } else { @@ -52,6 +53,10 @@ object UpdateCheckerManager { } else { CheckUpdateResult(hasUpdate = false) } + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to check for updates: ${e.message}") + return@withContext CheckUpdateResult(hasUpdate = false, error = e.message) + } } suspend fun downloadApk(context: Context, downloadUrl: String): File? = withContext(Dispatchers.IO) { diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt index f53697bb..8ef7a7b7 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt @@ -16,6 +16,7 @@ import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean import com.v2ray.ang.extension.isNotNullEmpty import com.v2ray.ang.fmt.HttpFmt +import com.v2ray.ang.fmt.Hysteria2Fmt import com.v2ray.ang.fmt.ShadowsocksFmt import com.v2ray.ang.fmt.SocksFmt import com.v2ray.ang.fmt.TrojanFmt @@ -97,7 +98,7 @@ object V2rayConfigManager { val result = ConfigResult(false) val address = config.server ?: return result - if (!Utils.isPureIpAddress(address)) { + if (!Utils.isIpAddress(address)) { if (!Utils.isValidUrl(address)) { Log.w(AppConfig.TAG, "$address is an invalid ip or domain") return result @@ -131,10 +132,7 @@ object V2rayConfigManager { v2rayConfig.policy = null } - //Resolve and add to DNS Hosts - if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") == "1") { - resolveOutboundDomainsToHosts(v2rayConfig) - } + resolveOutboundDomainsToHosts(v2rayConfig) result.status = true result.content = JsonUtil.toJsonPretty(v2rayConfig) ?: "" @@ -154,7 +152,7 @@ object V2rayConfigManager { val result = ConfigResult(false) val address = config.server ?: return result - if (!Utils.isPureIpAddress(address)) { + if (!Utils.isIpAddress(address)) { if (!Utils.isValidUrl(address)) { Log.w(AppConfig.TAG, "$address is an invalid ip or domain") return result @@ -481,25 +479,6 @@ object V2rayConfigManager { ) } - //block dns - val blkDomain = getUserRule2Domain(AppConfig.TAG_BLOCKED) - if (blkDomain.isNotEmpty()) { - hosts.putAll(blkDomain.map { it to AppConfig.LOOPBACK }) - } - - // hardcode googleapi rule to fix play store problems - hosts[AppConfig.GOOGLEAPIS_CN_DOMAIN] = AppConfig.GOOGLEAPIS_COM_DOMAIN - - // hardcode popular Android Private DNS rule to fix localhost DNS problem - hosts[AppConfig.DNS_ALIDNS_DOMAIN] = AppConfig.DNS_ALIDNS_ADDRESSES - hosts[AppConfig.DNS_CLOUDFLARE_ONE_DOMAIN] = AppConfig.DNS_CLOUDFLARE_ONE_ADDRESSES - hosts[AppConfig.DNS_CLOUDFLARE_DNS_COM_DOMAIN] = AppConfig.DNS_CLOUDFLARE_DNS_COM_ADDRESSES - hosts[AppConfig.DNS_CLOUDFLARE_DNS_DOMAIN] = AppConfig.DNS_CLOUDFLARE_DNS_ADDRESSES - hosts[AppConfig.DNS_DNSPOD_DOMAIN] = AppConfig.DNS_DNSPOD_ADDRESSES - hosts[AppConfig.DNS_GOOGLE_DOMAIN] = AppConfig.DNS_GOOGLE_ADDRESSES - hosts[AppConfig.DNS_QUAD9_DOMAIN] = AppConfig.DNS_QUAD9_ADDRESSES - hosts[AppConfig.DNS_YANDEX_DOMAIN] = AppConfig.DNS_YANDEX_ADDRESSES - //User DNS hosts try { val userHosts = MmkvManager.decodeSettingsString(AppConfig.PREF_DNS_HOSTS) @@ -514,6 +493,24 @@ object V2rayConfigManager { Log.e(AppConfig.TAG, "Failed to configure user DNS hosts", e) } + //block dns + val blkDomain = getUserRule2Domain(AppConfig.TAG_BLOCKED) + if (blkDomain.isNotEmpty()) { + hosts.putAll(blkDomain.map { it to AppConfig.LOOPBACK }) + } + + // hardcode googleapi rule to fix play store problems + hosts[AppConfig.GOOGLEAPIS_CN_DOMAIN] = AppConfig.GOOGLEAPIS_COM_DOMAIN + + // hardcode popular Android Private DNS rule to fix localhost DNS problem + hosts[AppConfig.DNS_ALIDNS_DOMAIN] = AppConfig.DNS_ALIDNS_ADDRESSES + hosts[AppConfig.DNS_CLOUDFLARE_DOMAIN] = AppConfig.DNS_CLOUDFLARE_ADDRESSES + hosts[AppConfig.DNS_DNSPOD_DOMAIN] = AppConfig.DNS_DNSPOD_ADDRESSES + hosts[AppConfig.DNS_GOOGLE_DOMAIN] = AppConfig.DNS_GOOGLE_ADDRESSES + hosts[AppConfig.DNS_QUAD9_DOMAIN] = AppConfig.DNS_QUAD9_ADDRESSES + hosts[AppConfig.DNS_YANDEX_DOMAIN] = AppConfig.DNS_YANDEX_ADDRESSES + + // DNS dns v2rayConfig.dns = V2rayConfig.DnsBean( servers = servers, @@ -831,11 +828,7 @@ object V2rayConfigManager { for (item in proxyOutboundList) { val domain = item.getServerAddress() if (domain.isNullOrEmpty()) continue - - if (newHosts.containsKey(domain)) { - item.ensureSockopt().domainStrategy = if (preferIpv6) "UseIPv6v4" else "UseIPv4v6" - continue - } + if (newHosts.containsKey(domain)) continue val resolvedIps = HttpUtil.resolveHostToIP(domain, preferIpv6) if (resolvedIps.isNullOrEmpty()) continue @@ -1052,15 +1045,7 @@ object V2rayConfigManager { fun populateTlsSettings(streamSettings: StreamSettingsBean, profileItem: ProfileItem, sniExt: String?) { val streamSecurity = profileItem.security.orEmpty() val allowInsecure = profileItem.insecure == true - val sni = if (profileItem.sni.isNullOrEmpty()) { - when { - sniExt.isNotNullEmpty() && Utils.isDomainName(sniExt) -> sniExt - profileItem.server.isNotNullEmpty() && Utils.isDomainName(profileItem.server) -> profileItem.server - else -> sniExt - } - } else { - profileItem.sni - } + val sni = if (profileItem.sni.isNullOrEmpty()) sniExt else profileItem.sni val fingerprint = profileItem.fingerPrint val alpns = profileItem.alpn val publicKey = profileItem.publicKey diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt index 7aecf634..db12287d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt @@ -25,13 +25,14 @@ class QSTileService : TileService() { * @param state The state to set. */ fun setState(state: Int) { - qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name) if (state == Tile.STATE_INACTIVE) { qsTile?.state = Tile.STATE_INACTIVE qsTile?.label = getString(R.string.app_name) + qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name) } else if (state == Tile.STATE_ACTIVE) { qsTile?.state = Tile.STATE_ACTIVE qsTile?.label = V2RayServiceManager.getRunningServerName() + qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name) } qsTile?.updateTile() @@ -44,11 +45,7 @@ class QSTileService : TileService() { override fun onStartListening() { super.onStartListening() - if (V2RayServiceManager.isRunning()) { - setState(Tile.STATE_ACTIVE) - } else { - setState(Tile.STATE_INACTIVE) - } + setState(Tile.STATE_INACTIVE) mMsgReceive = ReceiveMessageHandler(this) val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY) ContextCompat.registerReceiver(applicationContext, mMsgReceive, mFilter, Utils.receiverFlags()) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayServiceManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayServiceManager.kt index 4f42ca23..659158a5 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayServiceManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayServiceManager.kt @@ -102,7 +102,7 @@ object V2RayServiceManager { val config = MmkvManager.decodeServerConfig(guid) ?: return if (config.configType != EConfigType.CUSTOM && !Utils.isValidUrl(config.server) - && !Utils.isPureIpAddress(config.server.orEmpty()) + && !Utils.isIpAddress(config.server) ) return // val result = V2rayConfigUtil.getV2rayConfig(context, guid) // if (!result.status) return diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt index d734c299..9fc24d56 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt @@ -33,7 +33,12 @@ import java.lang.ref.SoftReference class V2RayVpnService : VpnService(), ServiceControl { companion object { private const val VPN_MTU = 1500 + private const val PRIVATE_VLAN4_CLIENT = "10.10.14.1" + private const val PRIVATE_VLAN4_ROUTER = "10.10.14.2" + private const val PRIVATE_VLAN6_CLIENT = "fc00::10:10:14:1" + private const val PRIVATE_VLAN6_ROUTER = "fc00::10:10:14:2" private const val TUN2SOCKS = "libtun2socks.so" + } private lateinit var mInterface: ParcelFileDescriptor @@ -155,15 +160,14 @@ class V2RayVpnService : VpnService(), ServiceControl { // If the old interface has exactly the same parameters, use it! // Configure a builder while parsing the parameters. val builder = Builder() - val vpnConfig = SettingsManager.getCurrentVpnInterfaceAddressConfig() //val enableLocalDns = defaultDPreference.getPrefBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false) builder.setMtu(VPN_MTU) - builder.addAddress(vpnConfig.ipv4Client, 30) + builder.addAddress(PRIVATE_VLAN4_CLIENT, 30) //builder.addDnsServer(PRIVATE_VLAN4_ROUTER) val bypassLan = SettingsManager.routingRulesetsBypassLan() if (bypassLan) { - AppConfig.ROUTED_IP_LIST.forEach { + AppConfig.BYPASS_PRIVATE_IP_LIST.forEach { val addr = it.split('/') builder.addRoute(addr[0], addr[1].toInt()) } @@ -172,10 +176,9 @@ class V2RayVpnService : VpnService(), ServiceControl { } if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) { - builder.addAddress(vpnConfig.ipv6Client, 126) + builder.addAddress(PRIVATE_VLAN6_CLIENT, 126) if (bypassLan) { builder.addRoute("2000::", 3) //currently only 1/8 of total ipV6 is in use - builder.addRoute("fc00::", 18) //Xray-core default FakeIPv6 Pool } else { builder.addRoute("::", 0) } @@ -256,10 +259,9 @@ class V2RayVpnService : VpnService(), ServiceControl { private fun runTun2socks() { Log.i(AppConfig.TAG, "Start run $TUN2SOCKS") val socksPort = SettingsManager.getSocksPort() - val vpnConfig = SettingsManager.getCurrentVpnInterfaceAddressConfig() val cmd = arrayListOf( File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath, - "--netif-ipaddr", vpnConfig.ipv4Router, + "--netif-ipaddr", PRIVATE_VLAN4_ROUTER, "--netif-netmask", "255.255.255.252", "--socks-server-addr", "$LOOPBACK:${socksPort}", "--tunmtu", VPN_MTU.toString(), @@ -270,7 +272,7 @@ class V2RayVpnService : VpnService(), ServiceControl { if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6)) { cmd.add("--netif-ip6addr") - cmd.add(vpnConfig.ipv6Router) + cmd.add(PRIVATE_VLAN6_ROUTER) } if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED)) { val localDnsPort = Utils.parseInt(MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt()) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt index a9b698c5..8f464a49 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt @@ -1,7 +1,6 @@ package com.v2ray.ang.ui import android.os.Bundle -import android.util.Log import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope import com.v2ray.ang.AppConfig @@ -10,7 +9,6 @@ import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityCheckUpdateBinding import com.v2ray.ang.dto.CheckUpdateResult import com.v2ray.ang.extension.toast -import com.v2ray.ang.extension.toastError import com.v2ray.ang.extension.toastSuccess import com.v2ray.ang.handler.MmkvManager import com.v2ray.ang.handler.SpeedtestManager @@ -48,16 +46,11 @@ class CheckUpdateActivity : BaseActivity() { toast(R.string.update_checking_for_update) lifecycleScope.launch { - try { - val result = UpdateCheckerManager.checkForUpdate(includePreRelease) - if (result.hasUpdate) { - showUpdateDialog(result) - } else { - toastSuccess(R.string.update_already_latest_version) - } - } catch (e: Exception) { - Log.e(AppConfig.TAG, "Failed to check for updates: ${e.message}") - toastError(e.message ?: getString(R.string.toast_failure)) + val result = UpdateCheckerManager.checkForUpdate(includePreRelease) + if (result.hasUpdate) { + showUpdateDialog(result) + } else { + toastSuccess(R.string.update_already_latest_version) } } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt index 6af64e3a..4ec2294a 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt @@ -44,7 +44,6 @@ class SettingsActivity : BaseActivity() { private val localDnsPort by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_PORT) } private val vpnDns by lazy { findPreference(AppConfig.PREF_VPN_DNS) } private val vpnBypassLan by lazy { findPreference(AppConfig.PREF_VPN_BYPASS_LAN) } - private val vpnInterfaceAddress by lazy { findPreference(AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX) } private val mux by lazy { findPreference(AppConfig.PREF_MUX_ENABLED) } private val muxConcurrency by lazy { findPreference(AppConfig.PREF_MUX_CONCURRENCY) } @@ -250,14 +249,12 @@ class SettingsActivity : BaseActivity() { listOf( AppConfig.PREF_VPN_BYPASS_LAN, - AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX, AppConfig.PREF_ROUTING_DOMAIN_STRATEGY, AppConfig.PREF_MUX_XUDP_QUIC, AppConfig.PREF_FRAGMENT_PACKETS, AppConfig.PREF_LANGUAGE, AppConfig.PREF_UI_MODE_NIGHT, AppConfig.PREF_LOGLEVEL, - AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, AppConfig.PREF_MODE ).forEach { key -> if (MmkvManager.decodeSettingsString(key) != null) { @@ -276,7 +273,7 @@ class SettingsActivity : BaseActivity() { localDnsPort?.isEnabled = vpn vpnDns?.isEnabled = vpn vpnBypassLan?.isEnabled = vpn - vpnInterfaceAddress?.isEnabled = vpn + vpn if (vpn) { updateLocalDns( MmkvManager.decodeSettingsBool( diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt index 7172728e..9e08f663 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt @@ -18,14 +18,12 @@ import java.net.URL object HttpUtil { /** - * Converts the domain part of a URL string to its IDN (Punycode, ASCII Compatible Encoding) format. + * Converts a URL string to its ASCII representation. * - * For example, a URL like "https://例子.中国/path" will be converted to "https://xn--fsqu00a.xn--fiqs8s/path". - * - * @param str The URL string to convert (can contain non-ASCII characters in the domain). - * @return The URL string with the domain part converted to ASCII-compatible (Punycode) format. + * @param str The URL string to convert. + * @return The ASCII representation of the URL. */ - fun toIdnUrl(str: String): String { + fun idnToASCII(str: String): String { val url = URL(str) val host = url.host val asciiHost = IDN.toASCII(url.host, IDN.ALLOW_UNASSIGNED) @@ -36,28 +34,6 @@ object HttpUtil { } } - /** - * Converts a Unicode domain name to its IDN (Punycode, ASCII Compatible Encoding) format. - * If the input is an IP address or already an ASCII domain, returns the original string. - * - * @param domain The domain string to convert (can include non-ASCII internationalized characters). - * @return The domain in ASCII-compatible (Punycode) format, or the original string if input is an IP or already ASCII. - */ - fun toIdnDomain(domain: String): String { - // Return as is if it's a pure IP address (IPv4 or IPv6) - if (Utils.isPureIpAddress(domain)) { - return domain - } - - // Return as is if already ASCII (English domain or already punycode) - if (domain.all { it.code < 128 }) { - return domain - } - - // Otherwise, convert to ASCII using IDN - return IDN.toASCII(domain, IDN.ALLOW_UNASSIGNED) - } - /** * Resolves a hostname to an IP address, returns original input if it's already an IP * diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/PluginUtil.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/PluginUtil.kt index 2b9f71aa..48e04b6d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/PluginUtil.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/PluginUtil.kt @@ -28,17 +28,13 @@ object PluginUtil { fun runPlugin(context: Context, config: ProfileItem?, socksPort: Int?) { Log.i(AppConfig.TAG, "Starting plugin execution") - if (config == null) { + if (config == null || socksPort == null) { Log.w(AppConfig.TAG, "Cannot run plugin: config is null") return } try { if (config.configType == EConfigType.HYSTERIA2) { - if (socksPort == null) { - Log.w(AppConfig.TAG, "Cannot run plugin: socksPort is null") - return - } Log.i(AppConfig.TAG, "Running Hysteria2 plugin") val configFile = genConfigHy2(context, config, socksPort) ?: return val cmd = genCmdHy2(context, configFile) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt index 148ce4ec..6a61afe5 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt @@ -198,21 +198,6 @@ object Utils { return isIpv4Address(value) || isIpv6Address(value) } - /** - * Check if a string is a valid domain name. - * - * A valid domain name must not be an IP address and must be a valid URL format. - * - * @param input The string to check. - * @return True if the string is a valid domain name, false otherwise. - */ - fun isDomainName(input: String?): Boolean { - if (input.isNullOrEmpty()) return false - - // Must not be an IP address and must be a valid URL format - return !isPureIpAddress(input) && isValidUrl(input) - } - /** * Check if a string is a valid IPv4 address. * diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt index 7ac5d60f..d78b1307 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt @@ -41,7 +41,6 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application AppConfig.PREF_MODE, AppConfig.PREF_VPN_DNS, AppConfig.PREF_VPN_BYPASS_LAN, - AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX, AppConfig.PREF_REMOTE_DNS, AppConfig.PREF_DOMESTIC_DNS, AppConfig.PREF_DNS_HOSTS, @@ -49,7 +48,6 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PREF_SOCKS_PORT, AppConfig.PREF_LOGLEVEL, - AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, AppConfig.PREF_LANGUAGE, AppConfig.PREF_UI_MODE_NIGHT, AppConfig.PREF_ROUTING_DOMAIN_STRATEGY, diff --git a/V2rayNG/app/src/main/res/values-ar/strings.xml b/V2rayNG/app/src/main/res/values-ar/strings.xml index d74011e9..49b724b1 100644 --- a/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -141,7 +141,6 @@ الإعدادات إعدادات متقدمة - إعدادات النواة إعدادات VPN الوكيل لكل تطبيق عام: التطبيق المحدد هو وكيل، غير المحدد اتصال مباشر؛ \nوضع التجاوز: التطبيق المحدد متصل مباشرة، غير المحدد وكيل. \nخيار تحديد تطبيق الوكيل تلقائيًا في القائمة @@ -182,8 +181,6 @@ VPN DNS (IPv4/v6 فقط) Does VPN bypass LAN - VPN Interface Address - DNS المحلي (اختياري) DNS @@ -241,7 +238,6 @@ فاصل التحديث التلقائي (بالدقائق، الحد الأدنى للقيمة 15) مستوى السجل - Outbound domain pre-resolve method الوضع انقر هنا للحصول على مزيد من المساعدة اللغة @@ -358,10 +354,4 @@ Not Bypass - - Do not resolve - Resolve and add to DNS Hosts - Resolve and replace domain - - diff --git a/V2rayNG/app/src/main/res/values-bn/strings.xml b/V2rayNG/app/src/main/res/values-bn/strings.xml index f36c9d3a..bd7c492f 100644 --- a/V2rayNG/app/src/main/res/values-bn/strings.xml +++ b/V2rayNG/app/src/main/res/values-bn/strings.xml @@ -139,7 +139,6 @@ সেটিংস এডভান্সড সেটিংস - কোর সেটিংস VPN সেটিংস প্রতি-অ্যাপ প্রক্সি সাধারণ: চেকড অ্যাপ প্রক্সি, আনচেকড সরাসরি সংযোগ; \nবাইপাস মোড: চেকড অ্যাপ সরাসরি সংযুক্ত, আনচেকড প্রক্সি। \nমেনুতে প্রক্সি অ্যাপ্লিকেশন স্বয়ংক্রিয়ভাবে নির্বাচন করার বিকল্প @@ -182,8 +181,6 @@ VPN DNS (শুধুমাত্র IPv4/v6) Does VPN bypass LAN - VPN Interface Address - ঘরোয়া DNS (ঐচ্ছিক) DNS @@ -241,7 +238,6 @@ অটো আপডেট ইন্টারভ্যাল (মিনিট, সর্বনিম্ন মান ১৫) লগ স্তর - Outbound domain pre-resolve method মোড আরো সাহায্যের জন্য ক্লিক করুন ভাষা @@ -363,10 +359,4 @@ Not Bypass - - Do not resolve - Resolve and add to DNS Hosts - Resolve and replace domain - - \ No newline at end of file diff --git a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml index 90e5cc26..41e81fbb 100644 --- a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml +++ b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml @@ -140,7 +140,6 @@ سامووا سامووا پؽش رئڌه - سامووا هسته سامووا VPN پروکسی و ری برنومه پوی وولاتی: برنومه واجۊری بیڌه پروکسی هڌ، منپیز موستقیم بؽ نشووه هڌ. هالت دور زیڌن: برنومه نشووک ناڌه موستقیمن منپیز هڌ، پروکسی نشووک زیڌه نؽڌ. گۊزینه پسند خوتکار برنومه پروکسی من نومگه @@ -168,7 +167,7 @@ ز نوم دامنه sniffed تینا سی تور جوستن استفاڌه کۊنین وو نشۊوی مۉرد نزرن و عونوان نشۊوی IP ووردارین. ر وندن DNS مهلی - درخاستا DNS و هسته و من ایان وو و دست ماژول DNS پردازشت ابۊن (پؽشنهاڌ ابۊ ٱر لنگ تور جوستن سی دور زیڌن نشۊویا LAN وو وولات ٱسلی هڌین فعال بۊ) + DNS پردازشت وابیڌه و دس هسته ماژول DNS (پؽشنهاڌ ابۊ، ٱر نیاز هڌ ک جوستن تور وو ولات ٱسلین دور زنی) ر وندن DNS جئلی DNS مهلی نشۊویا IP جئلی ن وورگنه (زل تر، ٱما گاشڌ من یقرد ز برنومه یل کار نکونه) @@ -176,18 +175,16 @@ ترجی IPv6 تورا IPv6 ن فعال کۊنین وو نشۊویا IPv6 ن ترجی بڌین - ز ر دیر (اختیاری) DNS (udp/tcp/https/quic) (اختیاری) + DNS ز ر دیر (اختیاری) (udp/tcp/https/quic) (اختیاری) DNS VPN DNS (تینا IPv4/v6) - ز شبکه مهلی اگوڌرته؟ VPN + VPN ز شبکه مهلی اگوڌرته؟ - نشۊوی رابت VPN - - منی (اختیاری) DNS + DNS منی (اختیاری) DNS - هاست موستقیم (قالوو: دامنه: نشۊوی،...) DNS + DNS هاست موستقیم (قالوو: دامنه: نشۊوی،...) دامنه:نشۊوی،... نشۊوی اینترنتی آزمایش تئخیر واقعی (http/https) @@ -207,20 +204,20 @@ پورت DNS مهلی قوۊل کردن پاک کردن کانفیگ - سی پاک وابیڌن فایل کانفیگ نیاز به قوۊل کردن دووارته ز سمت منتور هڌ. + سی پاک وابیڌن فایل کانفیگ نیاز به قوۊل کردن دووارته ز سمت منتور هڌ زی اسکنن ر ون - شؽواتگرن سی اسکن، زی مجال ر وندن بۊگۊشین، ٱندی ترین کودن اسکن کۊنین یا شؽواتی ن منه نوار ٱوزار پسند کۊنین. + شؽواتگرن سی اسکن، زی مجال ر وندن بۊگۊشین، اندی ترین کودن اسکن کۊنین یا شؽواتی ن منه نوار ٱوزار پسند کۊنین. پروکسی HTTP ن و VPN ازاف کۊنین پروکسی HTTP ن موسقیمن ز (مۊرۊرگر/ی قرد ز برنومه یل لادراری بیڌه)، بؽ استفاڌه ز دسگا NIC مجازی (Android 10+) استفاڌه ابۊ. ر وندن نشۉݩ داڌن دو سۊتۊنی - نومگه نمایه یل من دو سۊتۊن نشۉݩ داڌه ابۊن وو چینۉ ترین موئتوا بیشتری ن سیل کۊنین. سی ر وستن، وا برنومه ن ز نۊ ر ونین. + نومگه نمایه یل من دو سۊتۊن نشۉݩ داڌه ابۊن وو چینۉ ترین موئتوا بیشتری ن سیل کۊنین. سی ر وستن وا برنومه ن ز نۊ ر ونین. فشناڌن منشڌ - فشناڌن منشڌ یا داسووݩ موشکلا من Github + فشناڌن منشڌ یا داسوو موشکلا من Github ٱووڌن من جرگه تلگرام برنومه تلگرامن نجوست هریم سیخومی @@ -241,7 +238,6 @@ فاسله ورۊ کردن خوتکار (اقلن وا 15 دؽقه بۊ) سئت داسووا - بارت پؽش هل دامنه دری هالت سی دووسمندیا وو هیاری بیشتر، ری ای هؽل بزݩ زۉݩ @@ -373,10 +369,4 @@ دور زیڌه نبۊ - - هل وو فسل مکۊنین - هل وو ٱووردن و میزبووݩ یل دامنه DNS - هل وو جایونی دامنه - - diff --git a/V2rayNG/app/src/main/res/values-fa/strings.xml b/V2rayNG/app/src/main/res/values-fa/strings.xml index 081571a3..16bbd4ff 100644 --- a/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -137,7 +137,6 @@ تنظیمات تنظیمات پیشرفته - تنظیمات هسته تنظیمات VPN پروکسی به تفکیک برنامه عمومی: برنامه انتخاب شده از طریق یک پروکسی متصل می شود، برنامه انتخاب نشده مستقیماً متصل می شود. \nحالت دور زدن: برنامه انتخاب شده مستقیماً متصل می شود، برنامه انتخاب نشده از طریق یک پروکسی متصل می شود. \nانتخاب خودکار برنامه های پراکسی در منو امکان پذیر است. @@ -180,8 +179,6 @@ VPN DNS (فقط IPv4/v6) آیا VPN از شبکه محلی عبور می کند؟ - VPN Interface Address - DNS داخلی (اختیاری) DNS @@ -238,7 +235,6 @@ اشتراک های خود را به طور خودکار با فاصله زمانی در پس زمینه به روز کنید. بسته به دستگاه، این ویژگی ممکن است همیشه کار نکند. فاصله به‌ روزرسانی خودکار ( حداقل مقدار ، 15 دقیقه ) سطح گزارشات - Outbound domain pre-resolve method حالت برای اطلاعات و راهنمایی بیشتر، روی این متن کلیک کنید زبان @@ -372,10 +368,4 @@ دور زده نشود - - Do not resolve - Resolve and add to DNS Hosts - Resolve and replace domain - - diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml index c71054a0..9b5e39f6 100644 --- a/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -139,7 +139,6 @@ Настройки Расширенные настройки - Настройки ядра Настройки VPN Прокси для выбранных приложений Основной: выбранное приложение соединяется через прокси, не выбранное — напрямую;\nРежим обхода: выбранное приложение соединяется напрямую, не выбранное — через прокси.\nЕсть возможность автоматического выбора проксируемых приложений в меню. @@ -181,8 +180,6 @@ VPN DNS (только IPv4/v6) VPN пропускает LAN - VPN частный IP - Внутренняя DNS (необязательно) DNS @@ -240,7 +237,6 @@ Интервал автообновления (минут, не менее 15) Подробность ведения журнала - Outbound domain pre-resolve method Режим Нажмите для получения дополнительной информации Язык @@ -372,10 +368,4 @@ Не пропускает - - Do not resolve - Resolve and add to DNS Hosts - Resolve and replace domain - - diff --git a/V2rayNG/app/src/main/res/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml index 86238b79..72cdee64 100644 --- a/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -138,7 +138,6 @@ Cài đặt Cài đặt nâng cao - Cài đặt lõi Cài đặt VPN Proxy theo Ứng dụng - Bình thường: Ứng dụng đã chọn sẽ kết nối thông qua Proxy, chưa chọn sẽ kết nối trực tiếp. \n- Chế độ Bypass: Ứng dụng đã chọn sẽ kết nối trực tiếp, chưa chọn sẽ kết nối qua Proxy. \n- Nếu bạn đang ở Trung Quốc thì vào Menu, chọn Tự động chọn ứng dụng Proxy. @@ -182,8 +181,6 @@ VPN DNS (Chỉ IPv4 / IPv6) Does VPN bypass LAN - VPN Interface Address - DNS nội địa (Không bắt buộc) DNS @@ -241,7 +238,6 @@ Thời gian cập nhật tự động (Phút, giá trị tối thiểu là 15) Cấp độ nhật ký - Outbound domain pre-resolve method Chế độ kết nối Nhấn vào đây nếu bạn cần trợ giúp! Ngôn ngữ @@ -360,10 +356,4 @@ Not Bypass - - Do not resolve - Resolve and add to DNS Hosts - Resolve and replace domain - - diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index a8eec856..a0aa7a5a 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -137,7 +137,6 @@ 设置 进阶设置 - 核心设置 VPN 设置 分应用 常规: 勾选的 App 被代理, 未勾选的直连;\n绕行模式: 勾选的 App 直连, 未勾选的被代理.\n不明白者在菜单中选择自动选中需代理应用 @@ -179,8 +178,6 @@ VPN DNS (仅支持 IPv4/v6) VPN 是否绕过局域网 - VPN 接口地址 - 境内 DNS (可选) DNS @@ -238,7 +235,6 @@ 自动更新间隔(分钟,最小值 15) 日志级别 - Outbound 域名预解析方式 模式 点此查看更多帮助 语言 @@ -364,10 +360,4 @@ 不绕过 - - 不解析 - 解析后添加至 DNS Hosts - 解析后替换原域名 - - diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index f8b938c5..e655e18f 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -138,7 +138,6 @@ 設定 進階 - 核心設定 VPN 設定 Proxy 個別應用程式 常規:勾選的 App 啟用 Proxy,未勾選的直接連線;\n繞行模式:勾選的 App 直接連線,未勾選的啟用 Proxy。\n可在選單中選擇自動選中需 Proxy 應用 @@ -181,8 +180,6 @@ VPN DNS (僅支援 IPv4/v6) VPN 是否繞過區域網 - VPN 介面位址 - DNS 境内 DNS (可选) DNS hosts (格式: 網域:位址,…) @@ -239,7 +236,6 @@ 自動更新間隔(分鐘,最小值 15) 記錄層級 - Outbound 網域預解析方式 模式 輕觸以檢視說明 語言 @@ -364,10 +360,4 @@ 不繞過 - - 不解析 - 解析後加入 DNS Hosts - 解析後替換原網域名稱 - - diff --git a/V2rayNG/app/src/main/res/values/arrays.xml b/V2rayNG/app/src/main/res/values/arrays.xml index 27f0846e..1863ccdd 100644 --- a/V2rayNG/app/src/main/res/values/arrays.xml +++ b/V2rayNG/app/src/main/res/values/arrays.xml @@ -182,30 +182,4 @@ 2 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - - - - 10.10.14.x - 10.1.0.x - 10.0.0.x - 172.31.0.x - 172.20.0.x - 172.16.0.x - 192.168.100.x - - - - 0 - 1 - 2 - - \ No newline at end of file diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index 57106306..39defc59 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -140,7 +140,6 @@ Settings Advanced Settings - Core Settings VPN Settings Per-app proxy General: Checked apps use proxy, unchecked apps connect directly; \nBypass mode: checked apps connect directly, unchecked apps use proxy. \nThe option to automatically select proxy applications is in the menu @@ -183,8 +182,6 @@ VPN DNS (only IPv4/v6) Does VPN bypass LAN - VPN Interface Address - Domestic DNS (Optional) DNS @@ -242,7 +239,6 @@ Auto Update Interval (Minutes, Min value 15) Log Level - Outbound domain pre-resolve method Mode Click me for more help Language @@ -374,10 +370,4 @@ Not Bypass - - Do not resolve - Resolve and add to DNS Hosts - Resolve and replace domain - - diff --git a/V2rayNG/app/src/main/res/xml/pref_settings.xml b/V2rayNG/app/src/main/res/xml/pref_settings.xml index b5ee7aab..75cad848 100644 --- a/V2rayNG/app/src/main/res/xml/pref_settings.xml +++ b/V2rayNG/app/src/main/res/xml/pref_settings.xml @@ -20,9 +20,9 @@ + android:key="pref_prefer_ipv6" + android:summary="@string/summary_pref_prefer_ipv6" + android:title="@string/title_pref_prefer_ipv6" /> - - @@ -179,7 +171,9 @@ android:title="@string/title_pref_auto_update_interval" /> - + + + - - - - - - - - + - - \ No newline at end of file diff --git a/V2rayNG/app/src/test/java/com/v2ray/ang/HttpUtilTest.kt b/V2rayNG/app/src/test/java/com/v2ray/ang/HttpUtilTest.kt index 07d87f4d..207215e5 100644 --- a/V2rayNG/app/src/test/java/com/v2ray/ang/HttpUtilTest.kt +++ b/V2rayNG/app/src/test/java/com/v2ray/ang/HttpUtilTest.kt @@ -10,31 +10,31 @@ class HttpUtilTest { fun testIdnToASCII() { // Regular URL remains unchanged val regularUrl = "https://example.com/path" - assertEquals(regularUrl, HttpUtil.toIdnUrl(regularUrl)) + assertEquals(regularUrl, HttpUtil.idnToASCII(regularUrl)) // Non-ASCII URL converts to ASCII (Punycode) val nonAsciiUrl = "https://例子.测试/path" val expectedNonAscii = "https://xn--fsqu00a.xn--0zwm56d/path" - assertEquals(expectedNonAscii, HttpUtil.toIdnUrl(nonAsciiUrl)) + assertEquals(expectedNonAscii, HttpUtil.idnToASCII(nonAsciiUrl)) // Mixed URL only converts the host part val mixedUrl = "https://例子.com/测试" val expectedMixed = "https://xn--fsqu00a.com/测试" - assertEquals(expectedMixed, HttpUtil.toIdnUrl(mixedUrl)) + assertEquals(expectedMixed, HttpUtil.idnToASCII(mixedUrl)) // URL with Basic Authentication using regular domain val basicAuthUrl = "https://user:password@example.com/path" - assertEquals(basicAuthUrl, HttpUtil.toIdnUrl(basicAuthUrl)) + assertEquals(basicAuthUrl, HttpUtil.idnToASCII(basicAuthUrl)) // URL with Basic Authentication using non-ASCII domain val basicAuthNonAscii = "https://user:password@例子.测试/path" val expectedBasicAuthNonAscii = "https://user:password@xn--fsqu00a.xn--0zwm56d/path" - assertEquals(expectedBasicAuthNonAscii, HttpUtil.toIdnUrl(basicAuthNonAscii)) + assertEquals(expectedBasicAuthNonAscii, HttpUtil.idnToASCII(basicAuthNonAscii)) // URL with non-ASCII username and password val nonAsciiAuth = "https://用户:密码@example.com/path" // Basic auth credentials should remain unchanged as they're percent-encoded separately - assertEquals(nonAsciiAuth, HttpUtil.toIdnUrl(nonAsciiAuth)) + assertEquals(nonAsciiAuth, HttpUtil.idnToASCII(nonAsciiAuth)) } diff --git a/V2rayNG/gradle/libs.versions.toml b/V2rayNG/gradle/libs.versions.toml index 04900e8c..97e74cbf 100644 --- a/V2rayNG/gradle/libs.versions.toml +++ b/V2rayNG/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.10.1" +agp = "8.10.0" desugarJdkLibs = "2.1.5" gradleLicensePlugin = "0.9.8" kotlin = "2.1.21" @@ -7,7 +7,7 @@ coreKtx = "1.16.0" junit = "4.13.2" junitVersion = "1.2.1" espressoCore = "3.6.1" -appcompat = "1.7.1" +appcompat = "1.7.0" material = "1.12.0" activity = "1.10.1" constraintlayout = "2.2.1" @@ -20,8 +20,8 @@ swiperefreshlayout = "1.1.0" toasty = "1.5.2" editorkit = "2.9.0" core = "3.5.3" -workRuntimeKtx = "2.10.2" -lifecycleViewmodelKtx = "2.9.1" +workRuntimeKtx = "2.10.1" +lifecycleViewmodelKtx = "2.9.0" multidex = "2.0.1" mockitoMockitoInline = "5.2.0" flexbox = "3.0.0"