Resolves hostnames in config (#4508)
* Removes IP resolution and resolves in config * Resolves hostnames to multiple IPs for DNS * Improves custom config handling
This commit is contained in:
@@ -583,4 +583,9 @@ data class V2rayConfig(
|
||||
return null
|
||||
}
|
||||
|
||||
fun getAllProxyOutbound(): List<OutboundBean> {
|
||||
return outbounds.filter { outbound ->
|
||||
EConfigType.entries.any { it.name.equals(outbound.protocol, ignoreCase = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,8 +302,4 @@ open class FmtBase {
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveHostToIP(server: String?): String {
|
||||
return HttpUtil.resolveHostToIP(server.orEmpty(), MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ object HttpFmt : FmtBase() {
|
||||
val outboundBean = OutboundBean.create(EConfigType.HTTP)
|
||||
|
||||
outboundBean?.settings?.servers?.first()?.let { server ->
|
||||
server.address = resolveHostToIP(profileItem.server)
|
||||
server.address = profileItem.server.orEmpty()
|
||||
server.port = profileItem.serverPort.orEmpty().toInt()
|
||||
if (profileItem.username.isNotNullEmpty()) {
|
||||
val socksUsersBean = OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
|
||||
@@ -134,7 +134,7 @@ object ShadowsocksFmt : FmtBase() {
|
||||
val outboundBean = OutboundBean.create(EConfigType.SHADOWSOCKS)
|
||||
|
||||
outboundBean?.settings?.servers?.first()?.let { server ->
|
||||
server.address = resolveHostToIP(profileItem.server)
|
||||
server.address = profileItem.server.orEmpty()
|
||||
server.port = profileItem.serverPort.orEmpty().toInt()
|
||||
server.password = profileItem.password
|
||||
server.method = profileItem.method
|
||||
|
||||
@@ -63,7 +63,7 @@ object SocksFmt : FmtBase() {
|
||||
val outboundBean = OutboundBean.create(EConfigType.SOCKS)
|
||||
|
||||
outboundBean?.settings?.servers?.first()?.let { server ->
|
||||
server.address = resolveHostToIP(profileItem.server)
|
||||
server.address = profileItem.server.orEmpty()
|
||||
server.port = profileItem.serverPort.orEmpty().toInt()
|
||||
if (profileItem.username.isNotNullEmpty()) {
|
||||
val socksUsersBean = OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
|
||||
@@ -63,7 +63,7 @@ object TrojanFmt : FmtBase() {
|
||||
val outboundBean = OutboundBean.create(EConfigType.TROJAN)
|
||||
|
||||
outboundBean?.settings?.servers?.first()?.let { server ->
|
||||
server.address = resolveHostToIP(profileItem.server)
|
||||
server.address = profileItem.server.orEmpty()
|
||||
server.port = profileItem.serverPort.orEmpty().toInt()
|
||||
server.password = profileItem.password
|
||||
server.flow = profileItem.flow
|
||||
|
||||
@@ -59,7 +59,7 @@ object VlessFmt : FmtBase() {
|
||||
val outboundBean = OutboundBean.create(EConfigType.VLESS)
|
||||
|
||||
outboundBean?.settings?.vnext?.first()?.let { vnext ->
|
||||
vnext.address = resolveHostToIP(profileItem.server)
|
||||
vnext.address = profileItem.server.orEmpty()
|
||||
vnext.port = profileItem.serverPort.orEmpty().toInt()
|
||||
vnext.users[0].id = profileItem.password.orEmpty()
|
||||
vnext.users[0].encryption = profileItem.method
|
||||
|
||||
@@ -171,7 +171,7 @@ object VmessFmt : FmtBase() {
|
||||
val outboundBean = OutboundBean.create(EConfigType.VMESS)
|
||||
|
||||
outboundBean?.settings?.vnext?.first()?.let { vnext ->
|
||||
vnext.address = resolveHostToIP(profileItem.server)
|
||||
vnext.address = profileItem.server.orEmpty()
|
||||
vnext.port = profileItem.serverPort.orEmpty().toInt()
|
||||
vnext.users[0].id = profileItem.password.orEmpty()
|
||||
vnext.users[0].security = profileItem.method
|
||||
|
||||
@@ -113,7 +113,7 @@ object WireguardFmt : FmtBase() {
|
||||
wireguard.peers?.firstOrNull()?.let { peer ->
|
||||
peer.publicKey = profileItem.publicKey.orEmpty()
|
||||
peer.preSharedKey = profileItem.preSharedKey?.takeIf { it.isNotEmpty() }
|
||||
peer.endpoint = Utils.getIpv6Address(resolveHostToIP(profileItem.server)) + ":${profileItem.serverPort}"
|
||||
peer.endpoint = Utils.getIpv6Address(profileItem.server) + ":${profileItem.serverPort}"
|
||||
}
|
||||
wireguard.mtu = profileItem.mtu
|
||||
wireguard.reserved = profileItem.reserved?.takeIf { it.isNotBlank() }?.split(",")?.filter { it.isNotBlank() }?.map { it.trim().toInt() }
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.v2ray.ang.fmt.TrojanFmt
|
||||
import com.v2ray.ang.fmt.VlessFmt
|
||||
import com.v2ray.ang.fmt.VmessFmt
|
||||
import com.v2ray.ang.fmt.WireguardFmt
|
||||
import com.v2ray.ang.util.HttpUtil
|
||||
import com.v2ray.ang.util.JsonUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
@@ -150,6 +151,8 @@ object V2rayConfigManager {
|
||||
v2rayConfig.policy = null
|
||||
}
|
||||
|
||||
resolveProxyDomainsToHosts(v2rayConfig)
|
||||
|
||||
result.status = true
|
||||
result.content = JsonUtil.toJsonPretty(v2rayConfig) ?: ""
|
||||
result.domainPort = if (retMore.first) retMore.second else retOut.second
|
||||
@@ -763,4 +766,32 @@ object V2rayConfigManager {
|
||||
|
||||
}
|
||||
|
||||
private fun resolveProxyDomainsToHosts(v2rayConfig: V2rayConfig) {
|
||||
val proxyOutboundList = v2rayConfig.getAllProxyOutbound()
|
||||
val dns = v2rayConfig.dns ?: return
|
||||
|
||||
val newHosts = dns.hosts?.toMutableMap() ?: mutableMapOf()
|
||||
|
||||
for (item in proxyOutboundList) {
|
||||
val domain = item.getServerAddress()
|
||||
if (domain.isNullOrEmpty()) continue
|
||||
|
||||
if (newHosts.containsKey(domain)) continue
|
||||
|
||||
val resolvedIps = HttpUtil.resolveHostToIP(
|
||||
domain,
|
||||
MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true
|
||||
)
|
||||
|
||||
if (resolvedIps.isEmpty()) continue
|
||||
|
||||
newHosts[domain] = if (resolvedIps.size == 1) {
|
||||
resolvedIps[0]
|
||||
} else {
|
||||
resolvedIps
|
||||
}
|
||||
}
|
||||
|
||||
dns.hosts = newHosts
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.IDN
|
||||
import java.net.InetAddress
|
||||
import java.net.Inet6Address
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.net.URL
|
||||
@@ -40,37 +41,38 @@ object HttpUtil {
|
||||
* @param ipv6Preferred Whether to prefer IPv6 addresses, defaults to false
|
||||
* @return The resolved IP address or the original input (if it's already an IP or resolution fails)
|
||||
*/
|
||||
fun resolveHostToIP(host: String, ipv6Preferred: Boolean = false): String {
|
||||
fun resolveHostToIP(host: String, ipv6Preferred: Boolean = false): List<String> {
|
||||
try {
|
||||
// If it's already an IP address, return it directly
|
||||
// If it's already an IP address, return it as a list
|
||||
if (Utils.isPureIpAddress(host)) {
|
||||
return host
|
||||
return listOf(host)
|
||||
}
|
||||
|
||||
// Get all IP addresses
|
||||
val addresses = InetAddress.getAllByName(host)
|
||||
if (addresses.isEmpty()) {
|
||||
return host
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// Sort addresses based on preference
|
||||
val sortedAddresses = if (ipv6Preferred) {
|
||||
// IPv6 preferred (size 16 first, then size 4)
|
||||
addresses.sortedByDescending { it.address.size }
|
||||
addresses.sortedWith(compareByDescending { it is Inet6Address })
|
||||
} else {
|
||||
// IPv4 preferred (size 4 first, then size 16)
|
||||
addresses.sortedBy { it.address.size }
|
||||
addresses.sortedWith(compareBy { it is Inet6Address })
|
||||
}
|
||||
Log.i(AppConfig.TAG, "Resolved IPs for $host: ${sortedAddresses.joinToString { it.hostAddress ?: "unknown" }}")
|
||||
|
||||
// Return the first address after sorting
|
||||
return sortedAddresses.first().hostAddress ?: host
|
||||
val ipList = sortedAddresses.mapNotNull { it.hostAddress }
|
||||
|
||||
Log.i(AppConfig.TAG, "Resolved IPs for $host: ${ipList.joinToString()}")
|
||||
|
||||
return ipList
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to resolve host to IP", e)
|
||||
return host
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the content of a URL as a string.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user