From c48fbd3fc81fac857d17dfadb05aaf354430559e Mon Sep 17 00:00:00 2001 From: cin <49077173+jimmand@users.noreply.github.com> Date: Mon, 21 Sep 2026 09:42:56 +0300 Subject: [PATCH] feat(wireguard): add remoteDNS field to server config UI (#6230) Expose the `remoteDNS` option (added in Xray-core 26.9.9) in the wireguard. - Accepts a comma-separated list of IPv4/IPv6 addresses - Accepts "local" as a single value to resolve via the device's local DNS instead of routing lookups through the tunnel - Falls back to WIREGUARD_LOCAL_REMOTE_DNS when the field is empty (Xray-core upstream value) Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com> --- .../src/main/java/com/v2ray/ang/AppConfig.kt | 1 + .../com/v2ray/ang/core/CoreOutboundBuilder.kt | 17 +++++++++++++++++ .../main/java/com/v2ray/ang/dto/V2rayConfig.kt | 1 + .../com/v2ray/ang/dto/entities/ProfileItem.kt | 1 + .../main/java/com/v2ray/ang/fmt/WireguardFmt.kt | 5 +++++ .../com/v2ray/ang/ui/server/ServerUiState.kt | 5 +++++ .../ang/ui/server/ServerWireguardActivity.kt | 6 ++++++ V2rayNG/app/src/main/res/values-ar/strings.xml | 1 + V2rayNG/app/src/main/res/values-bn/strings.xml | 1 + .../app/src/main/res/values-bqi-rIR/strings.xml | 1 + V2rayNG/app/src/main/res/values-fa/strings.xml | 1 + V2rayNG/app/src/main/res/values-ru/strings.xml | 1 + V2rayNG/app/src/main/res/values-vi/strings.xml | 1 + .../app/src/main/res/values-zh-rCN/strings.xml | 1 + .../app/src/main/res/values-zh-rTW/strings.xml | 1 + V2rayNG/app/src/main/res/values/strings.xml | 1 + 16 files changed, 45 insertions(+) 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 942d54536..5991e561c 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt @@ -166,6 +166,7 @@ object AppConfig { const val WIREGUARD_LOCAL_ADDRESS_V4 = "172.16.0.2/32" const val WIREGUARD_LOCAL_ADDRESS_V6 = "2606:4700:110:8f81:d551:a0:532e:a2b3/128" const val WIREGUARD_LOCAL_MTU = "1420" + const val WIREGUARD_LOCAL_REMOTE_DNS = "1.1.1.1,1.0.0.1,2606:4700:4700::1111,2606:4700:4700::1001" const val LOOPBACK = "127.0.0.1" /** Shared defaults for settings shown in the UI and consumed by config generation. */ diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreOutboundBuilder.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreOutboundBuilder.kt index 85406608e..54ccfb58e 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreOutboundBuilder.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreOutboundBuilder.kt @@ -252,6 +252,22 @@ object CoreOutboundBuilder { ipv4Addresses.ifEmpty { listOf(AppConfig.WIREGUARD_LOCAL_ADDRESS_V4) } } + val rawDNS = profileItem.remoteDNS + ?.split(",") + ?.map { it.trim() } + ?.filter { it.isNotEmpty() } + ?.ifEmpty { null } + ?: listOf(AppConfig.WIREGUARD_LOCAL_REMOTE_DNS) + + val remotes = if (rawDNS.size == 1 && rawDNS[0] == "local") { + rawDNS + } else if (MmkvManager.decodeSettingsBool(AppConfig.PREF_IPV6_ENABLED) == true) { + rawDNS + } else { + val ipv4Dns = rawDNS.filter { !it.contains(":") } + ipv4Dns.ifEmpty { listOf(AppConfig.WIREGUARD_LOCAL_REMOTE_DNS) } + } + outboundBean?.settings?.let { wireguard -> wireguard.secretKey = profileItem.secretKey wireguard.address = addresses @@ -262,6 +278,7 @@ object CoreOutboundBuilder { peer.endpoint = Utils.getIpv6Address(profileItem.server) + ":${profileItem.serverPort}" } wireguard.mtu = profileItem.mtu + wireguard.remoteDNS = remotes wireguard.reserved = profileItem.reserved?.takeIf { it.isNotBlank() }?.split(",")?.filter { it.isNotBlank() }?.map { it.trim().toInt() } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt index f4876afb6..6e87fb268 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt @@ -98,6 +98,7 @@ data class V2rayConfig( val peers: List? = null, var reserved: List? = null, var mtu: Int? = null, + var remoteDNS: List? = null, var domainStrategy: String? = null, ) { data class WireGuardBean( diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/entities/ProfileItem.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/entities/ProfileItem.kt index 9b2af45e5..7eb270c57 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/entities/ProfileItem.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/entities/ProfileItem.kt @@ -56,6 +56,7 @@ data class ProfileItem( var localAddress: String? = null, var reserved: String? = null, var mtu: Int? = null, + var remoteDNS: String? = null, var obfsPassword: String? = null, var portHopping: String? = null, diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt index 15e0125c0..be300acd9 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt @@ -32,6 +32,7 @@ object WireguardFmt : FmtBase() { config.publicKey = queryParam["publickey"].orEmpty() config.preSharedKey = queryParam["presharedkey"]?.nullIfBlank() config.mtu = Utils.parseInt(queryParam["mtu"] ?: AppConfig.WIREGUARD_LOCAL_MTU) + config.remoteDNS = queryParam["dns"] ?: AppConfig.WIREGUARD_LOCAL_REMOTE_DNS config.reserved = queryParam["reserved"] ?: "0,0,0" config.finalMask = (queryParam["fm"] ?: queryParam["finalmask"] ?: queryParam["finalMask"])?.nullIfBlank() @@ -82,6 +83,7 @@ object WireguardFmt : FmtBase() { config.remarks = System.currentTimeMillis().toString() config.localAddress = interfaceParams["address"] ?: AppConfig.WIREGUARD_LOCAL_ADDRESS_V4 config.mtu = Utils.parseInt(interfaceParams["mtu"] ?: AppConfig.WIREGUARD_LOCAL_MTU) + config.remoteDNS = interfaceParams["dns"] ?: AppConfig.WIREGUARD_LOCAL_REMOTE_DNS config.publicKey = peerParams["publickey"].orEmpty() config.preSharedKey = peerParams["presharedkey"]?.nullIfBlank() val endpoint = peerParams["endpoint"].orEmpty() @@ -120,6 +122,9 @@ object WireguardFmt : FmtBase() { if (config.preSharedKey != null) { dicQuery["presharedkey"] = config.preSharedKey.removeWhiteSpace().orEmpty() } + if (config.remoteDNS != null) { + dicQuery["dns"] = config.remoteDNS.removeWhiteSpace().orEmpty() + } config.finalMask?.nullIfBlank()?.let { dicQuery["fm"] = it } return toUri(config, config.secretKey, dicQuery) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerUiState.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerUiState.kt index 3961bc3b6..4da11994a 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerUiState.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerUiState.kt @@ -8,6 +8,7 @@ import com.v2ray.ang.AppConfig.DEFAULT_PORT import com.v2ray.ang.AppConfig.REALITY import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4 import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_MTU +import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_REMOTE_DNS import com.v2ray.ang.dto.entities.ProfileItem import com.v2ray.ang.enums.EConfigType import com.v2ray.ang.enums.NetworkType @@ -30,6 +31,7 @@ class ServerUiState( reserved: String = "0,0,0", localAddress: String = WIREGUARD_LOCAL_ADDRESS_V4, mtu: String = WIREGUARD_LOCAL_MTU, + remoteDNS: String = WIREGUARD_LOCAL_REMOTE_DNS, obfsPassword: String = "", portHopping: String = "", portHoppingInterval: String = "", @@ -78,6 +80,7 @@ class ServerUiState( var reserved by mutableStateOf(reserved) var localAddress by mutableStateOf(localAddress) var mtu by mutableStateOf(mtu) + var remoteDNS by mutableStateOf(remoteDNS) var obfsPassword by mutableStateOf(obfsPassword) var portHopping by mutableStateOf(portHopping) var portHoppingInterval by mutableStateOf(portHoppingInterval) @@ -142,6 +145,7 @@ class ServerUiState( reserved = if (isWireguard) reserved else null, localAddress = if (isWireguard) localAddress else null, mtu = if (isWireguard) mtu.toIntOrNull() else null, + remoteDNS = if (isWireguard) remoteDNS else null, obfsPassword = if (isHysteria2) obfsPassword else null, portHopping = if (isHysteria2) portHopping else null, portHoppingInterval = if (isHysteria2) portHoppingInterval else null, @@ -199,6 +203,7 @@ class ServerUiState( reserved = initialConfig.reserved ?: "0,0,0", localAddress = initialConfig.localAddress ?: WIREGUARD_LOCAL_ADDRESS_V4, mtu = initialConfig.mtu?.toString() ?: WIREGUARD_LOCAL_MTU, + remoteDNS = initialConfig.remoteDNS ?: WIREGUARD_LOCAL_REMOTE_DNS, obfsPassword = initialConfig.obfsPassword ?: "", portHopping = initialConfig.portHopping ?: "", portHoppingInterval = initialConfig.portHoppingInterval ?: "", diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerWireguardActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerWireguardActivity.kt index 44954ada0..0ea5c7ba1 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerWireguardActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/server/ServerWireguardActivity.kt @@ -73,6 +73,12 @@ class ServerWireguardActivity : BaseServerActivity() { state.finalMask, { state.finalMask = it } ) + + FormTextField( + stringResource(R.string.server_lab_remote_dns), + state.remoteDNS, + { state.remoteDNS = it } + ) } } diff --git a/V2rayNG/app/src/main/res/values-ar/strings.xml b/V2rayNG/app/src/main/res/values-ar/strings.xml index ebeae87f1..9ccaeb6d3 100644 --- a/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -100,6 +100,7 @@ Reserved (اختياري، مفصول بفواصل) العنوان المحلي (اختياري IPv4/IPv6، مفصولة بفواصل) MTU (اختياري، الافتراضي 1420) + remoteDNS (اختياري، عناوين IPv4/IPv6 مفصولة بفواصل، أو "local" لاستخدام DNS الجهاز) mKCP MTU (اختياري، الافتراضي 1350) mKCP TTI (اختياري، الافتراضي 50 مللي ثانية) نجاح diff --git a/V2rayNG/app/src/main/res/values-bn/strings.xml b/V2rayNG/app/src/main/res/values-bn/strings.xml index 57756f7e7..aacd34940 100644 --- a/V2rayNG/app/src/main/res/values-bn/strings.xml +++ b/V2rayNG/app/src/main/res/values-bn/strings.xml @@ -100,6 +100,7 @@ Reserved (ঐচ্ছিক, কমা দিয়ে পৃথক) স্থানীয় ঠিকানা (ঐচ্ছিক IPv4/IPv6, কমা দ্বারা পৃথক করা) MTU (ঐচ্ছিক, ডিফল্ট 1420) + remoteDNS (ঐচ্ছিক, কমা দ্বারা পৃথক করা IPv4/IPv6 ঠিকানা, অথবা ডিভাইসের DNS ব্যবহার করতে "local") mKCP MTU (ঐচ্ছিক, ডিফল্ট 1350) mKCP TTI (ঐচ্ছিক, ডিফল্ট 50 মিলিসেকেন্ড) সফল 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 8b824b746..49309d754 100644 --- a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml +++ b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml @@ -100,6 +100,7 @@ Reserved(اختیاری، وا کاما (,) ز یک جوڌا ابۊن) نشۊوی محلی (اختیاری IPv4/IPv6، وا کاما (,) ز یک جوڌا ابۊن) MTU(اختیاری، پؽش فرض 1420) + remoteDNS (اختياری، آدرس‌های IPv4/IPv6 جدا شده با کاما، یا "local" برای استفاده از DNS دستگاه) mKCP MTU (اختیاری، پؽش فرض 1350) mKCP TTI (اختیاری، پؽش فرض 50 میلی‌ثانیه) وا مووفقیت ٱنجوم وابی diff --git a/V2rayNG/app/src/main/res/values-fa/strings.xml b/V2rayNG/app/src/main/res/values-fa/strings.xml index cb2211b6c..60a1d42eb 100644 --- a/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -100,6 +100,7 @@ Reserved (اختیاری، جدا شده با کاما) آدرس محلی (IPv4/IPv6 اختیاری، جدا شده با کاما) MTU (اختیاری، پیش‌فرض 1420) + remoteDNS (اختیاری، آدرس‌های IPv4/IPv6 جدا شده با کاما، یا "local" برای استفاده از DNS دستگاه) mKCP MTU (اختیاری، پیش‌فرض 1350) mKCP TTI (اختیاری، پیش‌فرض 50 میلی‌ثانیه) موفقیت‌آمیز diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml index 6e37d5162..9f9987d4d 100644 --- a/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -100,6 +100,7 @@ Reserved (необязательно, через запятую) Локальный адрес (необязательно, IPv4/IPv6 через запятую) MTU (необязательно, по умолчанию 1420) + remoteDNS (необязательно, IPv4/IPv6-адреса через запятую, либо "local" для использования локального DNS) mKCP MTU (необязательно, по умолчанию 1350) mKCP TTI (необязательно, по умолчанию 50 мс) Успешно diff --git a/V2rayNG/app/src/main/res/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml index 355b696a7..e6a4b08ef 100644 --- a/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -100,6 +100,7 @@ Reserved (không bắt buộc, phân cách bằng dấu phẩy) Địa chỉ cục bộ (IPv4/IPv6 không bắt buộc, phân cách bằng dấu phẩy) MTU (không bắt buộc, mặc định 1420) + remoteDNS (tùy chọn, các địa chỉ IPv4/IPv6 cách nhau bằng dấu phẩy, hoặc "local" để dùng DNS của thiết bị) mKCP MTU (không bắt buộc, mặc định 1350) mKCP TTI (không bắt buộc, mặc định 50 ms) Thành công! 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 37e88f10b..d1ea397b9 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -100,6 +100,7 @@ Reserved (可选,逗号隔开) 本地地址 (可选 IPv4/IPv6,逗号隔开) MTU(可选,默认 1420) + remoteDNS(可选,多个 IPv4/IPv6 地址用逗号分隔,或填写 "local" 使用设备本地 DNS) mKCP MTU(可选,默认 1350) mKCP TTI(可选,默认 50 毫秒) 成功 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 a2617856e..1f2b4ff15 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -100,6 +100,7 @@ Reserved (可選,逗號隔開) 本機位址 (可選 IPv4/IPv6,逗號隔開) MTU(可選,預設 1420) + remoteDNS(選填,多個 IPv4/IPv6 位址以逗號分隔,或輸入 "local" 使用裝置本機 DNS) mKCP MTU(可選,預設 1350) mKCP TTI(可選,預設 50 毫秒) 成功 diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index 334689d55..a50d2dcfb 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -100,6 +100,7 @@ Reserved (optional, separated by commas) Local address (optional IPv4/IPv6, separated by commas) MTU (optional, default 1420) + remoteDNS (optional, comma-separated IPv4/IPv6, or "local" to use device DNS) mKCP MTU (optional, default 1350) mKCP TTI (optional, default 50 ms) Success