diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt index 8fd587895..5f37e276a 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt @@ -18,8 +18,11 @@ object AppConfig { const val PREF_SNIFFING_ENABLED = "pref_sniffing_enabled" const val PREF_PROXY_SHARING = "pref_proxy_sharing_enabled" const val PREF_LOCAL_DNS_ENABLED = "pref_local_dns_enabled" + const val PREF_FAKE_DNS_ENABLED = "pref_fake_dns_enabled" + const val PREF_VPN_DNS = "pref_vpn_dns" const val PREF_REMOTE_DNS = "pref_remote_dns" const val PREF_DOMESTIC_DNS = "pref_domestic_dns" + const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port" const val PREF_FORWARD_IPV6 = "pref_forward_ipv6" const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy" const val PREF_ROUTING_MODE = "pref_routing_mode" diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt index 675fed2bf..5d05a1782 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt @@ -20,7 +20,7 @@ data class V2rayConfig( val api: Any? = null, val transport: Any? = null, val reverse: Any? = null, - val fakedns: Any? = null, + var fakedns: FakednsBean? = null, val browserForwarder: Any? = null) { companion object { const val DEFAULT_PORT = 443 @@ -57,7 +57,7 @@ data class V2rayConfig( val network: String? = null) data class SniffingBean(var enabled: Boolean, - val destOverride: List, + val destOverride: ArrayList, val metadataOnly: Boolean? = null) } @@ -78,7 +78,7 @@ data class V2rayConfig( val address: String? = null, val port: Int? = null, /*Freedom*/ - val domainStrategy: String? = null, + var domainStrategy: String? = null, val redirect: String? = null, val userLevel: Int? = null, /*Loopback*/ @@ -376,9 +376,9 @@ data class V2rayConfig( val tag: String? = null ) { data class ServersBean(var address: String = "", - var port: Int = 0, - var domains: List?, - var expectIPs: List?, + var port: Int? = null, + var domains: List? = null, + var expectIPs: List? = null, val clientIp: String? = null) } @@ -416,6 +416,9 @@ data class V2rayConfig( var bufferSize: Int? = null) } + data class FakednsBean(var ipPool: String = "198.18.0.0/15", + var poolSize: Int = 10000) // roughly 10 times smaller than total ip pool + fun getProxyOutbound(): OutboundBean? { outbounds.forEach { outbound -> if (outbound.protocol.equals(EConfigType.VMESS.name, true) || diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt index efc410ff4..0a21a3130 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt @@ -122,10 +122,12 @@ class V2RayVpnService : VpnService(), ServiceControl { } if(!enableLocalDns) { - Utils.getRemoteDnsServers() - .forEach { - builder.addDnsServer(it) - } + Utils.getVpnDnsServers() + .forEach { + if (Utils.isPureIpAddress(it)) { + builder.addDnsServer(it) + } + } } builder.setSession(V2RayServiceManager.currentConfig?.remarks.orEmpty()) diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt index c374b3b8d..786dbc8b0 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt @@ -4,6 +4,7 @@ import android.arch.lifecycle.ViewModelProviders import android.content.Intent import android.os.Bundle import android.support.v7.preference.* +import android.text.TextUtils import android.view.View import com.v2ray.ang.R import com.v2ray.ang.AppConfig @@ -29,6 +30,10 @@ class SettingsActivity : BaseActivity() { class SettingsFragment : PreferenceFragmentCompat() { private val perAppProxy by lazy { findPreference(AppConfig.PREF_PER_APP_PROXY) as CheckBoxPreference } + private val localDns by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_ENABLED) } + private val fakeDns by lazy { findPreference(AppConfig.PREF_FAKE_DNS_ENABLED) } + private val localDnsPort by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_PORT) } + private val vpnDns by lazy { findPreference(AppConfig.PREF_VPN_DNS) } private val sppedEnabled by lazy { findPreference(AppConfig.PREF_SPEED_ENABLED) as CheckBoxPreference } private val sniffingEnabled by lazy { findPreference(AppConfig.PREF_SNIFFING_ENABLED) as CheckBoxPreference } private val proxySharing by lazy { findPreference(AppConfig.PREF_PROXY_SHARING) as CheckBoxPreference } @@ -141,9 +146,21 @@ class SettingsActivity : BaseActivity() { restartProxy() true } - + localDns?.setOnPreferenceChangeListener{ _, any -> + updateLocalDns(any as Boolean) + true + } + localDnsPort?.setOnPreferenceChangeListener { _, any -> + val nval = any as String + localDnsPort?.summary = if (TextUtils.isEmpty(nval)) "10807" else nval + true + } + vpnDns?.setOnPreferenceChangeListener { _, any -> + vpnDns?.summary = any as String + true + } mode.setOnPreferenceChangeListener { _, newValue -> - updatePerAppProxy(newValue.toString()) + updateMode(newValue.toString()) true } mode.dialogLayoutResource = R.layout.preference_with_help_link @@ -188,32 +205,43 @@ class SettingsActivity : BaseActivity() { override fun onStart() { super.onStart() val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity) - updatePerAppProxy(defaultSharedPreferences.getString(AppConfig.PREF_MODE, "VPN")) - remoteDns.summary = defaultSharedPreferences.getString(AppConfig.PREF_REMOTE_DNS, "") + updateMode(defaultSharedPreferences.getString(AppConfig.PREF_MODE, "VPN")) + var remoteDnsString = defaultSharedPreferences.getString(AppConfig.PREF_REMOTE_DNS, "") domesticDns.summary = defaultSharedPreferences.getString(AppConfig.PREF_DOMESTIC_DNS, "") - if (remoteDns.summary == "") { - remoteDns.summary = AppConfig.DNS_AGENT + if (TextUtils.isEmpty(remoteDnsString)) { + remoteDnsString = AppConfig.DNS_AGENT } - if ( domesticDns.summary == "") { domesticDns.summary = AppConfig.DNS_DIRECT } + remoteDns.summary = remoteDnsString + vpnDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_VPN_DNS, remoteDnsString) // socksPort.summary = defaultSharedPreferences.getString(PREF_SOCKS_PORT, "10808") // lanconnPort.summary = defaultSharedPreferences.getString(PREF_HTTP_PORT, "") } - private fun updatePerAppProxy(mode: String?) { - if (mode == "VPN") { - perAppProxy.isEnabled = true - perAppProxy.isChecked = PreferenceManager.getDefaultSharedPreferences(activity) - .getBoolean(AppConfig.PREF_PER_APP_PROXY, false) - } else { - perAppProxy.isEnabled = false - perAppProxy.isChecked = false + private fun updateMode(mode: String?) { + val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity) + val vpn = mode == "VPN" + perAppProxy.isEnabled = vpn + perAppProxy.isChecked = PreferenceManager.getDefaultSharedPreferences(activity) + .getBoolean(AppConfig.PREF_PER_APP_PROXY, false) + localDns?.isEnabled = vpn + fakeDns?.isEnabled = vpn + localDnsPort?.isEnabled = vpn + vpnDns?.isEnabled = vpn + if (vpn) { + updateLocalDns(defaultSharedPreferences.getBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)) } } + + private fun updateLocalDns(enabled: Boolean) { + fakeDns?.isEnabled = enabled + localDnsPort?.isEnabled = enabled + vpnDns?.isEnabled = !enabled + } } fun onModeHelpClicked(view: View) { diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt index a619d7bfb..b905a3546 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt @@ -15,7 +15,6 @@ import android.content.ClipData import android.content.Intent import android.net.Uri import android.os.SystemClock -import android.text.TextUtils import android.util.Log import android.util.Patterns import android.webkit.URLUtil @@ -123,41 +122,31 @@ object Utils { /** * get remote dns servers from preference */ - fun getRemoteDnsServers(): ArrayList { + fun getRemoteDnsServers(): List { val remoteDns = settingsStorage?.decodeString(AppConfig.PREF_REMOTE_DNS) ?: AppConfig.DNS_AGENT - val ret = ArrayList() - if (!TextUtils.isEmpty(remoteDns)) { - remoteDns - .split(",") - .forEach { - if (Utils.isPureIpAddress(it)) { - ret.add(it) - } - } - } - if (ret.size == 0) { - ret.add(AppConfig.DNS_AGENT) + val ret = remoteDns.split(",").filter { isPureIpAddress(it) || it.startsWith("https") } + if (ret.isEmpty()) { + return listOf(AppConfig.DNS_AGENT) } return ret } + fun getVpnDnsServers(): List { + val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS) + ?: settingsStorage?.decodeString(AppConfig.PREF_REMOTE_DNS) + ?: AppConfig.DNS_AGENT + return vpnDns.split(",").filter { isPureIpAddress(it) } + // allow empty, in that case dns will use system default + } + /** * get remote dns servers from preference */ - fun getDomesticDnsServers(): ArrayList { + fun getDomesticDnsServers(): List { val domesticDns = settingsStorage?.decodeString(AppConfig.PREF_DOMESTIC_DNS) ?: AppConfig.DNS_DIRECT - val ret = ArrayList() - if (!TextUtils.isEmpty(domesticDns)) { - domesticDns - .split(",") - .forEach { - if (Utils.isPureIpAddress(it)) { - ret.add(it) - } - } - } - if (ret.size == 0) { - ret.add(AppConfig.DNS_DIRECT) + val ret = domesticDns.split(",").filter { isPureIpAddress(it) || it.startsWith("https") } + if (ret.isEmpty()) { + return listOf(AppConfig.DNS_DIRECT) } return ret } @@ -391,7 +380,7 @@ object Utils { val command = "/system/bin/ping -c 3 $url" val process = Runtime.getRuntime().exec(command) val allText = process.inputStream.bufferedReader().use { it.readText() } - if (!TextUtils.isEmpty(allText)) { + if (allText.isNotBlank()) { val tempInfo = allText.substring(allText.indexOf("min/avg/max/mdev") + 19) val temps = tempInfo.split("/".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray() if (temps.count() > 0 && temps[0].length < 10) { diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt index 94db3bb3b..e897050dc 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt @@ -8,15 +8,10 @@ import com.tencent.mmkv.MMKV import com.v2ray.ang.AppConfig import com.v2ray.ang.dto.V2rayConfig import com.v2ray.ang.dto.EConfigType +import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_NETWORK +import com.v2ray.ang.dto.V2rayConfig.Companion.HTTP object V2rayConfigUtil { -// private val requestObj: JsonObject by lazy { -// Gson().fromJson("""{"version":"1.1","method":"GET","path":["/"],"headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}""", JsonObject::class.java) -// } -// private val responseObj: JSONObject by lazy { -// JSONObject("""{"version":"1.1","status":"200","reason":"OK","headers":{"Content-Type":["application/octet-stream","video/mpeg"],"Transfer-Encoding":["chunked"],"Connection":["keep-alive"],"Pragma":"no-cache"}}""") -// } - private val serverRawStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SERVER_RAW, MMKV.MULTI_PROCESS_MODE) } private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) } @@ -66,10 +61,14 @@ object V2rayConfigUtil { inbounds(v2rayConfig) + httpRequestObject(outbound) + v2rayConfig.outbounds[0] = outbound routing(v2rayConfig) + fakedns(v2rayConfig) + if (settingsStorage?.decodeBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) { customLocalDns(v2rayConfig) } else { @@ -99,7 +98,17 @@ object V2rayConfigUtil { } } v2rayConfig.inbounds[0].port = 10808 - v2rayConfig.inbounds[0].sniffing?.enabled = settingsStorage?.decodeBool(AppConfig.PREF_SNIFFING_ENABLED) ?: true + val fakedns = settingsStorage?.decodeBool(AppConfig.PREF_FAKE_DNS_ENABLED) + ?: false + val sniffAllTlsAndHttp = settingsStorage?.decodeBool(AppConfig.PREF_SNIFFING_ENABLED) + ?: true + v2rayConfig.inbounds[0].sniffing?.enabled = fakedns || sniffAllTlsAndHttp + if (!sniffAllTlsAndHttp) { + v2rayConfig.inbounds[0].sniffing?.destOverride?.clear() + } + if (fakedns) { + v2rayConfig.inbounds[0].sniffing?.destOverride?.add("fakedns") + } //v2rayConfig.inbounds[1].port = httpPort @@ -116,16 +125,29 @@ object V2rayConfigUtil { return true } + private fun fakedns(v2rayConfig: V2rayConfig) { + if (settingsStorage?.decodeBool(AppConfig.PREF_FAKE_DNS_ENABLED) == true) { + v2rayConfig.fakedns = V2rayConfig.FakednsBean() + v2rayConfig.outbounds.filter { it.protocol == "freedom" }.forEach { + it.settings?.domainStrategy = "UseIP" + } + } + } + /** * routing */ private fun routing(v2rayConfig: V2rayConfig): Boolean { try { - routingUserRule(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT) ?: "", AppConfig.TAG_AGENT, v2rayConfig) - routingUserRule(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT) ?: "", AppConfig.TAG_DIRECT, v2rayConfig) - routingUserRule(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_BLOCKED) ?: "", AppConfig.TAG_BLOCKED, v2rayConfig) + routingUserRule(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT) + ?: "", AppConfig.TAG_AGENT, v2rayConfig) + routingUserRule(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT) + ?: "", AppConfig.TAG_DIRECT, v2rayConfig) + routingUserRule(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_BLOCKED) + ?: "", AppConfig.TAG_BLOCKED, v2rayConfig) - v2rayConfig.routing.domainStrategy = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY) ?: "IPIfNonMatch" + v2rayConfig.routing.domainStrategy = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY) + ?: "IPIfNonMatch" val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: "0" // Hardcode googleapis.cn @@ -242,31 +264,34 @@ object V2rayConfigUtil { val hosts = mutableMapOf() val servers = ArrayList() val remoteDns = Utils.getRemoteDnsServers() - - remoteDns.forEach { - servers.add(it) - } - val domesticDns = Utils.getDomesticDnsServers() val geositeCn = arrayListOf("geosite:cn") val geoipCn = arrayListOf("geoip:cn") + val proxyDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT) + ?: "") + val directDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT) + ?: "") - val agDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT) ?: "") - if (agDomain.size > 0) { - servers.add(V2rayConfig.DnsBean.ServersBean(remoteDns.first(), 53, agDomain, null)) + if (settingsStorage?.decodeBool(AppConfig.PREF_FAKE_DNS_ENABLED) == true) { + // fakedns with all domains to make it always top priority + servers.add(V2rayConfig.DnsBean.ServersBean(address = "fakedns", domains = geositeCn.plus(proxyDomain).plus(directDomain))) } - - val dirDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT) ?: "") - if (dirDomain.size > 0) { - servers.add(V2rayConfig.DnsBean.ServersBean(domesticDns.first(), 53, dirDomain, geoipCn)) + remoteDns.forEach { + servers.add(it) + } + if (proxyDomain.size > 0) { + servers.add(V2rayConfig.DnsBean.ServersBean(remoteDns.first(), 53, proxyDomain, null)) + } + if (directDomain.size > 0) { + servers.add(V2rayConfig.DnsBean.ServersBean(domesticDns.first(), 53, directDomain, geoipCn)) } - val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: "0" if (routingMode == "2" || routingMode == "3") { servers.add(V2rayConfig.DnsBean.ServersBean(domesticDns.first(), 53, geositeCn, geoipCn)) } - val blkDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_BLOCKED) ?: "") + val blkDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_BLOCKED) + ?: "") if (blkDomain.size > 0) { hosts.putAll(blkDomain.map { it to "127.0.0.1" }) } @@ -364,4 +389,27 @@ object V2rayConfigUtil { } return true } + + private fun httpRequestObject(outbound: V2rayConfig.OutboundBean): Boolean { + try { + if (outbound.streamSettings?.network == DEFAULT_NETWORK + && outbound.streamSettings?.tcpSettings?.header?.type == HTTP) { + val path = outbound.streamSettings?.tcpSettings?.header?.request?.path + val Host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host + + val requestString: String by lazy { + """{"version":"1.1","method":"GET","headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}""" + } + outbound.streamSettings?.tcpSettings?.header?.request = Gson().fromJson(requestString, V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean.RequestBean::class.java) + outbound.streamSettings?.tcpSettings?.header?.request?.path = path!! + outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host = Host!! + } + + } catch (e: Exception) { + e.printStackTrace() + return false + } + return true + } + } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt index 464f3e9ad..1cecc9b97 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt @@ -27,6 +27,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application Log.d(AppConfig.ANG_PACKAGE, "Observe settings changed: $key") when(key) { AppConfig.PREF_MODE, + AppConfig.PREF_VPN_DNS, AppConfig.PREF_REMOTE_DNS, AppConfig.PREF_DOMESTIC_DNS, AppConfig.PREF_ROUTING_DOMAIN_STRATEGY, @@ -39,6 +40,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application AppConfig.PREF_SPEED_ENABLED, AppConfig.PREF_PROXY_SHARING, AppConfig.PREF_LOCAL_DNS_ENABLED, + AppConfig.PREF_FAKE_DNS_ENABLED, AppConfig.PREF_FORWARD_IPV6, AppConfig.PREF_PER_APP_PROXY, AppConfig.PREF_BYPASS_APPS, -> { 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 24d13e72f..bfa8a8d73 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -76,7 +76,7 @@ 设置 进阶设置 - + VPN 设置 分应用代理 分应用代理仅支持 Android 5.0 Lollipop 及更高 @@ -87,10 +87,13 @@ 在通知中显示当前速度\n小图标显示流量的路由情况 启用流量探测 - 流量探测 + 从流量中探测域名 (默认启用) 启用本地DNS - DNS由本地设备的v2Ray-core处理(测试) + DNS 请求导入 core 由 DNS 模块处理(推荐启用 如果需要路由绕过局域网及大陆地址) + + 启用虚拟DNS + 本地返回虚构解析结果 (减低延时 但个别应用可能无法使用) IPv6 路由 转发 IPv6 流量到远程服务器(测试) @@ -107,7 +110,9 @@ 远程DNS (可选) DNS - 境内DNS (可选,本地DNS模式下生效) + VPN DNS (仅支持 IPv4/v6) + + 境内DNS (可选) DNS SOCKS5代理端口 @@ -116,6 +121,9 @@ HTTP代理端口 HTTP代理端口 + 本地DNS端口 + 本地DNS端口 + 反馈 反馈改进或漏洞至 GitHub 加入Telegram Group 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 4c6b7436b..416dbf7f6 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -77,7 +77,7 @@ 設定 進階設定 - + VPN 設定 Proxy 個別應用程式 Proxy 個別應用程式模式只支援 Android 5.0 (Lollipop) 或更高 @@ -88,10 +88,13 @@ 在通知中顯示當前速度\n小圖標顯示流量的路由情況 啟用流量探測 - 流量探測 + 從流量中探測域名 (默認啟用) 啟用本地DNS - DNS請求由本地的v2ray core處理(測試) + DNS 請求導入 core 由 DNS 模塊處理(推薦啟用 如果需要路由略過局域網及中國大陸) + + 啟用虛擬DNS + 本地返回虛構解析結果 (減低延時 但個別應用可能無法使用) IPv6 路由 向遠端重新導向 IPv6 流量(測試) @@ -108,7 +111,9 @@ 遠端DNS (可選) DNS - 境内DNS (可選,僅本地DNS模式下生效) + VPN DNS (僅支持 IPv4/v6) + + 境内DNS (可選) DNS SOCKS5代理連接埠 @@ -117,6 +122,8 @@ HTTP代理連接埠 HTTP代理連接埠 + 本地DNS端口 + 本地DNS端口 回饋 回饋提升或前往 GitHub 回報 Bug diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index f15c8c8bc..06782022b 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -77,7 +77,7 @@ Settings Advanced Settings - + VPN Settings Per-app proxy Per-app proxy mode only support Android 5.0 Lollipop or higher @@ -89,10 +89,14 @@ usage. Enable Sniffing - Sniffing + Try sniff domain from the packet (default on) Enable local DNS - DNS processed by v2ray-core (BETA) + DNS processed by core‘s DNS module (Recommended, if need routing Bypassing LAN and + mainland address) + + Enable fake DNS + local DNS returns fake IP address (faster, but it may not work for some apps) IPv6 Route Redirect IPv6 traffic to remote (BETA) @@ -109,7 +113,9 @@ Remote DNS (Optional) DNS - Domestic DNS (Optional, effects on LocalDNS mode) + VPN DNS (only IPv4/v6) + + Domestic DNS (Optional) DNS SOCKS5 proxy port @@ -118,6 +124,9 @@ HTTP proxy port HTTP proxy port + Local DNS port + Local DNS port + Feedback Feedback enhancements or bugs to GitHub Join Telegram Group diff --git a/V2rayNG/app/src/main/res/xml/pref_settings.xml b/V2rayNG/app/src/main/res/xml/pref_settings.xml index 021594a4a..7c1fe1510 100644 --- a/V2rayNG/app/src/main/res/xml/pref_settings.xml +++ b/V2rayNG/app/src/main/res/xml/pref_settings.xml @@ -1,6 +1,17 @@ - + + + + + + + android:key="pref_fake_dns_enabled" + android:summary="@string/summary_pref_fake_dns_enabled" + android:title="@string/title_pref_fake_dns_enabled" /> - + - + @@ -40,6 +53,11 @@ android:summary="%s" android:title="@string/title_pref_routing_domain_strategy" /> + + - - @@ -62,19 +75,11 @@ android:title="@string/title_pref_forward_ipv6" /> - - - - + android:defaultValue="false" + android:key="pref_proxy_sharing_enabled" + android:onClick="proxySharingOnClick" + android:summary="@string/summary_pref_proxy_sharing_enabled" + android:title="@string/title_pref_proxy_sharing_enabled" /> + + + +