You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
4.3 KiB
128 lines
4.3 KiB
|
2 years ago
|
package tv.anypoint.proxy.util
|
||
|
2 years ago
|
|
||
|
|
import jakarta.servlet.http.HttpServletRequest
|
||
|
|
import kotlinx.coroutines.*
|
||
|
|
import java.net.Inet4Address
|
||
|
|
import java.net.InetAddress
|
||
|
|
import java.net.NetworkInterface
|
||
|
|
import java.util.*
|
||
|
|
|
||
|
|
object NetworkUtil {
|
||
|
|
fun getPrivateIpV4(setTopBoxAddress: InetAddress): String = getPrivateIpV4List()
|
||
|
|
.chooseSimilarIp(setTopBoxAddress)?.hostAddress
|
||
|
2 years ago
|
?: throw RuntimeException("셋톱과 공유하는 private IP가 없습니다")
|
||
|
2 years ago
|
|
||
|
|
/**
|
||
|
|
* Gives the private IP of this device
|
||
|
|
* @return The private IP
|
||
|
|
*/
|
||
|
|
fun getPrivateIpV4List(): List<InetAddress> {
|
||
|
|
val result = mutableListOf<InetAddress>()
|
||
|
|
NetworkInterface.getNetworkInterfaces().forEach { n ->
|
||
|
|
result += n.inetAddresses.filter { it is Inet4Address && it.isSiteLocalAddress }
|
||
|
|
}
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gives the list of all open IPs of the private network
|
||
|
|
* in which this device is connected to.
|
||
|
|
*
|
||
|
|
* For the time saving, this method performs multithreaded
|
||
|
|
* ping test for 5 seconds in each thread, excluding
|
||
|
|
* 192.168.0.1 and this device's private IP.
|
||
|
|
*
|
||
|
|
* @return List of all open IPs as [InetAddress]
|
||
|
|
*/
|
||
|
|
fun findAllOpenPrivateIps(skipSelf: Boolean = false) = runBlocking {
|
||
|
|
val todos = mutableListOf<Deferred<Unit?>>()
|
||
|
|
val privateIpList = getPrivateIpV4List()
|
||
|
|
val available2dArray = Array(privateIpList.size) { arrayOfNulls<InetAddress>(256) }
|
||
|
|
|
||
|
|
privateIpList.forEachIndexed { i, inetAddress ->
|
||
|
|
todos += Inet4Iterator(inetAddress, skipSelf)
|
||
|
|
.map {
|
||
|
|
async(Dispatchers.IO) {
|
||
|
|
if (it.second.isReachable(1000)) available2dArray[i][it.first] = it.second else null
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
todos.awaitAll()
|
||
|
|
return@runBlocking available2dArray.flatten().filterNotNull()
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The iterator that iterates all near IPs from the given [originalIp]
|
||
|
|
*
|
||
|
|
* If the given IP is a.b.c.d, then it will iterate from
|
||
|
|
* a.b.c.2 to a.b.c.255, when start=2 and [end]=255 (default)
|
||
|
|
*/
|
||
|
|
class Inet4Iterator(
|
||
|
|
private val originalIp: InetAddress,
|
||
|
|
private val skipOriginal: Boolean = true,
|
||
|
|
start: UInt = 2u,
|
||
|
|
private val end: UInt = 255u
|
||
|
|
) : Iterator<Pair<Int, InetAddress>>, Iterable<Pair<Int, InetAddress>> {
|
||
|
|
|
||
|
|
private val a: UByte
|
||
|
|
private val b: UByte
|
||
|
|
private val c: UByte
|
||
|
|
private val skip: UByte
|
||
|
|
private var d = start
|
||
|
|
|
||
|
|
init {
|
||
|
|
val addressBytes = originalIp.address
|
||
|
|
a = addressBytes[0].toUByte()
|
||
|
|
b = addressBytes[1].toUByte()
|
||
|
|
c = addressBytes[2].toUByte()
|
||
|
|
skip = addressBytes[3].toUByte()
|
||
|
|
}
|
||
|
|
|
||
|
|
override fun hasNext(): Boolean {
|
||
|
|
return if (skipOriginal && skip == 0xFFu.toUByte()) d < end else d < (end + 1u)
|
||
|
|
}
|
||
|
|
|
||
|
|
override fun next(): Pair<Int, InetAddress> {
|
||
|
|
val result = Pair(d.toInt(), Inet4Util.fromIpClasses(a, b, c, d.toUByte()))
|
||
|
|
d += if (d == skip - 1u) 2u else 1u
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
|
||
|
|
override fun iterator() = this
|
||
|
|
}
|
||
|
|
|
||
|
|
object Inet4Util {
|
||
|
|
fun fromIpClasses(a: UByte, b: UByte, c: UByte, d: UByte): InetAddress {
|
||
|
|
return Inet4Address.getByName("$a.$b.$c.$d")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fun InetAddress.getIpClassSimilarity(other: InetAddress): Int {
|
||
|
|
if (this::class != other::class) return 0
|
||
|
|
val ipClasses = this.address
|
||
|
|
val otherIpClasses = other.address
|
||
|
|
|
||
|
|
for (i in 0 until ipClasses.size.coerceAtMost(otherIpClasses.size)) {
|
||
|
|
if (ipClasses[i] != otherIpClasses[i]) return i
|
||
|
|
}
|
||
|
|
return ipClasses.size
|
||
|
|
}
|
||
|
|
|
||
|
|
fun List<InetAddress>.chooseSimilarIp(other: InetAddress) = this.maxByOrNull { it.getIpClassSimilarity(other) }
|
||
|
|
|
||
|
|
fun <T> Enumeration<T>.forEach(block: (T) -> Unit) {
|
||
|
|
for (i in this) block(i)
|
||
|
|
}
|
||
|
|
|
||
|
|
fun <T> Enumeration<T>.filter(block: (T) -> Boolean): List<T> {
|
||
|
|
val result = mutableListOf<T>()
|
||
|
|
for (i in this) if (block(i)) result += i
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fun HttpServletRequest.getIpAddressString(): String = this.getHeader("X-FORWARDED-FOR") ?: this.remoteAddr
|
||
|
|
|
||
|
|
fun HttpServletRequest.getIpAddress(): InetAddress = InetAddress.getByName(this.getIpAddressString())
|