From 4e45661e264e34d1ea5a54b195938461de11e487 Mon Sep 17 00:00:00 2001
From: wwqgtxx <wwqgtxx@gmail.com>
Date: Mon, 17 Mar 2025 22:34:26 +0800
Subject: [PATCH] handle ipv6 address's scopeId for dns server

---
 .../com/github/kr328/clash/service/util/Address.kt  | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/service/src/main/java/com/github/kr328/clash/service/util/Address.kt b/service/src/main/java/com/github/kr328/clash/service/util/Address.kt
index d1c54c56..9ee5b32c 100644
--- a/service/src/main/java/com/github/kr328/clash/service/util/Address.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/util/Address.kt
@@ -7,7 +7,7 @@ import java.net.InetAddress
 fun InetAddress.asSocketAddressText(port: Int): String {
     return when (this) {
         is Inet6Address ->
-            "[${numericToTextFormat(this.address)}]:$port"
+            "[${numericToTextFormat(this)}]:$port"
         is Inet4Address ->
             "${this.hostAddress}:$port"
         else -> throw IllegalArgumentException("Unsupported Inet type ${this.javaClass}")
@@ -16,7 +16,8 @@ fun InetAddress.asSocketAddressText(port: Int): String {
 
 private const val INT16SZ = 2
 private const val INADDRSZ = 16
-private fun numericToTextFormat(src: ByteArray): String {
+private fun numericToTextFormat(address: Inet6Address): String {
+    var src = address.getAddress()
     val sb = StringBuilder(39)
     for (i in 0 until INADDRSZ / INT16SZ) {
         sb.append(
@@ -29,6 +30,14 @@ private fun numericToTextFormat(src: ByteArray): String {
             sb.append(":")
         }
     }
+    // handle [fe80::1%wlan0] like address from Inet6Address.getHostAddress()
+    // For the Android system, a ScopeId must be carried when initiating a connection to an ipv6 link-local address
+    // Note that the Scope must be returned as an int type, not a string format
+    // Reference: https://github.com/golang/go/issues/68082
+    if (address.getScopeId() > 0) {
+        sb.append("%")
+        sb.append(address.getScopeId())
+    }
     return sb.toString()
 }