Commit 0fa349ea authored by Mygod's avatar Mygod

Handle IPv6 addresses in hosts file

parent 7ea25c7c
...@@ -305,6 +305,7 @@ object BaseService { ...@@ -305,6 +305,7 @@ object BaseService {
listOfNotNull(data.proxy, data.udpFallback).forEach { it.trafficMonitor?.persistStats(it.profile.id) } listOfNotNull(data.proxy, data.udpFallback).forEach { it.trafficMonitor?.persistStats(it.profile.id) }
suspend fun preInit() { } suspend fun preInit() { }
suspend fun getActiveNetwork() = if (Build.VERSION.SDK_INT >= 23) Core.connectivity.activeNetwork else null
suspend fun resolver(host: String) = DnsResolverCompat.resolveOnActiveNetwork(host) suspend fun resolver(host: String) = DnsResolverCompat.resolveOnActiveNetwork(host)
suspend fun openConnection(url: URL) = url.openConnection() suspend fun openConnection(url: URL) = url.openConnection()
......
...@@ -39,6 +39,7 @@ import kotlinx.coroutines.withContext ...@@ -39,6 +39,7 @@ import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.Inet6Address
import java.net.URL import java.net.URL
import java.net.UnknownHostException import java.net.UnknownHostException
import java.security.MessageDigest import java.security.MessageDigest
...@@ -95,7 +96,10 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -95,7 +96,10 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
// it's hard to resolve DNS on a specific interface so we'll do it here // it's hard to resolve DNS on a specific interface so we'll do it here
if (profile.host.parseNumericAddress() == null) { if (profile.host.parseNumericAddress() == null) {
profile.host = (hosts.resolve(profile.host).firstOrNull() ?: try { // if fails/null, use IPv4 only, otherwise pick a random IPv4/IPv6 address
val hasIpv6 = service.getActiveNetwork()?.let { Core.connectivity.getLinkProperties(it) }?.linkAddresses
?.any { it.address is Inet6Address } == true
profile.host = (hosts.resolve(profile.host, if (hasIpv6) null else false).firstOrNull() ?: try {
service.resolver(profile.host).firstOrNull() service.resolver(profile.host).firstOrNull()
} catch (_: IOException) { } catch (_: IOException) {
null null
......
...@@ -140,6 +140,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -140,6 +140,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
} }
override suspend fun preInit() = DefaultNetworkListener.start(this) { underlyingNetwork = it } override suspend fun preInit() = DefaultNetworkListener.start(this) { underlyingNetwork = it }
override suspend fun getActiveNetwork() = DefaultNetworkListener.get()
override suspend fun resolver(host: String) = DnsResolverCompat.resolve(DefaultNetworkListener.get(), host) override suspend fun resolver(host: String) = DnsResolverCompat.resolve(DefaultNetworkListener.get(), host)
override suspend fun openConnection(url: URL) = DefaultNetworkListener.get().openConnection(url) override suspend fun openConnection(url: URL) = DefaultNetworkListener.get().openConnection(url)
......
...@@ -22,6 +22,8 @@ package com.github.shadowsocks.net ...@@ -22,6 +22,8 @@ package com.github.shadowsocks.net
import com.github.shadowsocks.utils.computeIfAbsentCompat import com.github.shadowsocks.utils.computeIfAbsentCompat
import com.github.shadowsocks.utils.parseNumericAddress import com.github.shadowsocks.utils.parseNumericAddress
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetAddress import java.net.InetAddress
class HostsFile(input: String = "") { class HostsFile(input: String = "") {
...@@ -35,5 +37,11 @@ class HostsFile(input: String = "") { ...@@ -35,5 +37,11 @@ class HostsFile(input: String = "") {
} }
val configuredHostnames get() = map.size val configuredHostnames get() = map.size
fun resolve(hostname: String) = map[hostname]?.shuffled() ?: emptyList() fun resolve(hostname: String, isIpv6: Boolean? = null): Collection<InetAddress> {
var result: Collection<InetAddress> = map[hostname] ?: return emptyList()
if (isIpv6 != null) {
result = if (isIpv6) result.filterIsInstance<Inet6Address>() else result.filterIsInstance<Inet4Address>()
}
return result.shuffled()
}
} }
...@@ -129,7 +129,7 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd ...@@ -129,7 +129,7 @@ class LocalDnsServer(private val localResolver: suspend (String) -> Array<InetAd
else -> return@supervisorScope remote.await() else -> return@supervisorScope remote.await()
} }
val host = question.name.toString(true) val host = question.name.toString(true)
val hostsResults = hosts.resolve(host) val hostsResults = hosts.resolve(host, isIpv6)
if (hostsResults.isNotEmpty()) { if (hostsResults.isNotEmpty()) {
remote.cancel() remote.cancel()
return@supervisorScope cookDnsResponse(request, hostsResults) return@supervisorScope cookDnsResponse(request, hostsResults)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment