Fix IP and CIDR validation (#6124)

This commit is contained in:
eliotcougar authored and GitHub committed 2026-08-23 15:56:32 +08:00
1 parent 63f557242b
commit dac65a972c
1 file changed
+15 -39
@@ -16,7 +16,6 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.LOOPBACK import com.v2ray.ang.AppConfig.LOOPBACK
import com.v2ray.ang.BuildConfig import com.v2ray.ang.BuildConfig
import java.io.IOException import java.io.IOException
import java.net.InetAddress
import java.net.ServerSocket import java.net.ServerSocket
import java.net.URI import java.net.URI
import java.net.URLDecoder import java.net.URLDecoder
@@ -213,8 +212,10 @@ object Utils {
*/ */
private fun isIpv6Address(value: String): Boolean { private fun isIpv6Address(value: String): Boolean {
var addr = value var addr = value
if (addr.startsWith("[") && addr.endsWith("]")) { if (addr.startsWith("[")) {
addr = addr.drop(1).dropLast(1) val closingBracket = addr.lastIndexOf(']')
if (closingBracket <= 1) return false
addr = addr.substring(1, closingBracket)
} }
return IPV6_REGEX.matches(addr) return IPV6_REGEX.matches(addr)
} }
@@ -460,48 +461,23 @@ object Utils {
fun isXray(): Boolean = BuildConfig.APPLICATION_ID.startsWith("com.v2ray.ang") fun isXray(): Boolean = BuildConfig.APPLICATION_ID.startsWith("com.v2ray.ang")
/** /**
* Converts an InetAddress to its long representation * Check if an IPv4 address is within an IPv4 CIDR range
* *
* @param ip The InetAddress to convert * @param ip The IPv4 address to check
* @return The long representation of the IP address * @param cidr The IPv4 CIDR range (e.g., "192.168.1.0/24")
*/
private fun inetAddressToLong(ip: InetAddress): Long {
val bytes = ip.address
var result: Long = 0
for (i in bytes.indices) {
result = result shl 8 or (bytes[i].toInt() and 0xff).toLong()
}
return result
}
/**
* Check if an IP address is within a CIDR range
*
* @param ip The IP address to check
* @param cidr The CIDR notation range (e.g., "192.168.1.0/24")
* @return True if the IP is within the CIDR range, false otherwise * @return True if the IP is within the CIDR range, false otherwise
*/ */
fun isIpInCidr(ip: String, cidr: String): Boolean { fun isIpInCidr(ip: String, cidr: String): Boolean {
try { val parts = cidr.split('/')
if (!isIpAddress(ip)) return false if (parts.size != 2 || !isIpv4Address(ip) || !isIpv4Address(parts[0])) return false
// Parse CIDR (e.g., "192.168.1.0/24") val prefixLength = parts[1].toIntOrNull()?.takeIf { it in 0..32 } ?: return false
val (cidrIp, prefixLen) = cidr.split("/") val mask = if (prefixLength == 0) 0L else (-1L shl (32 - prefixLength))
val prefixLength = prefixLen.toInt() return (ipv4ToLong(ip) and mask) == (ipv4ToLong(parts[0]) and mask)
}
// Convert IP and CIDR's IP portion to Long private fun ipv4ToLong(ip: String): Long {
val ipLong = inetAddressToLong(InetAddress.getByName(ip)) return ip.split('.').fold(0L) { result, octet -> (result shl 8) or octet.toLong() }
val cidrIpLong = inetAddressToLong(InetAddress.getByName(cidrIp))
// Calculate subnet mask (e.g., /24 → 0xFFFFFF00)
val mask = if (prefixLength == 0) 0L else (-1L shl (32 - prefixLength))
// Check if they're in the same subnet
return (ipLong and mask) == (cidrIpLong and mask)
} catch (e: Exception) {
LogUtil.e(AppConfig.TAG, "Failed to check if IP is in CIDR", e)
return false
}
} }
/** /**