close #116, ignore closedchannelexception, update ktor

This commit is contained in:
creeper123123321 2021-04-03 19:17:18 -03:00
parent 4faedc7894
commit f799856df1
5 changed files with 38 additions and 28 deletions

View File

@ -64,7 +64,7 @@ dependencies {
implementation("org.apache.commons:commons-compress:1.20")
implementation("org.tukaani:xz:1.9")
val ktorVersion = "1.5.2"
val ktorVersion = "1.5.3"
implementation(kotlin("stdlib-jdk8"))
implementation("io.ktor:ktor-network-tls-certificates:$ktorVersion")
implementation("io.ktor:ktor-server-netty:$ktorVersion")

View File

@ -25,8 +25,6 @@ import java.util.*
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import javax.naming.NameNotFoundException
import javax.naming.ServiceUnavailableException
import javax.naming.directory.InitialDirContext
val badLength = DecoderException("Invalid length!")
@ -41,7 +39,7 @@ fun resolveSrv(address: String, port: Int): Pair<String, Int> {
try {
// https://github.com/GeyserMC/Geyser/blob/99e72f35b308542cf0dbfb5b58816503c3d6a129/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
val attr = InitialDirContext()
.getAttributes("dns:///_minecraft._tcp.$address", arrayOf("SRV"))["SRV"]
.getAttributes("dns:///_minecraft._tcp.$address", arrayOf("SRV"))["SRV"]
if (attr != null && attr.size() > 0) {
val record = (attr.get(0) as String).split(" ")
return record[3] to record[2].toInt()
@ -75,8 +73,8 @@ fun mcCfb8(key: ByteArray, mode: Int): Cipher {
fun parseUndashedId(string: String): UUID {
Preconditions.checkArgument(string.length == 32, "Length is incorrect")
return UUID(
string.substring(0, 16).toULong(16).toLong(),
string.substring(16).toULong(16).toLong()
string.substring(0, 16).toULong(16).toLong(),
string.substring(16).toULong(16).toLong()
)
}
@ -95,7 +93,8 @@ fun twosComplementHexdigest(digest: ByteArray): String {
// https://github.com/VelocityPowered/Velocity/blob/e3f17eeb245b8d570f16c1f2aff5e7eafb698d5e/api/src/main/java/com/velocitypowered/api/util/UuidUtils.java
fun generateOfflinePlayerUuid(username: String) = UUID.nameUUIDFromBytes(
"OfflinePlayer:$username".toByteArray(Charsets.UTF_8))
"OfflinePlayer:$username".toByteArray(Charsets.UTF_8)
)
fun checkLocalAddress(inetAddress: InetAddress): Boolean {
return VIAaaSConfig.blockLocalAddress && (inetAddress.isAnyLocalAddress
@ -107,16 +106,15 @@ fun checkLocalAddress(inetAddress: InetAddress): Boolean {
|| inetAddress.isMCOrgLocal
|| inetAddress.isMCSiteLocal
|| NetworkInterface.networkInterfaces().flatMap { it.inetAddresses() }
.anyMatch {
// This public address acts like a localhost, let's block it
it == inetAddress
})
.anyMatch {
// This public address acts like a localhost, let's block it
it == inetAddress
})
}
fun matchesAddress(addr: InetSocketAddress, list: List<String>): Boolean {
return (matchAddress(addr.hostString, list)
|| (addr.address != null && (matchAddress(addr.address.hostAddress, list)
|| matchAddress(addr.address.hostName, list))))
return (matchAddress(addr.hostString, list) || (addr.address != null
&& (matchAddress(addr.address.hostAddress, list) || matchAddress(addr.address.hostName, list))))
}
private fun matchAddress(addr: String, list: List<String>): Boolean {
@ -157,9 +155,9 @@ fun ByteBuf.readByteArray(length: Int) = ByteArray(length).also { readBytes(it)
suspend fun hasJoined(username: String, hash: String): JsonObject {
return httpClient.get(
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" +
UrlEscapers.urlFormParameterEscaper().escape(username) +
"&serverId=$hash"
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" +
UrlEscapers.urlFormParameterEscaper().escape(username) +
"&serverId=$hash"
) ?: throw IllegalArgumentException("Couldn't authenticate with session servers")
}

View File

@ -9,6 +9,7 @@ import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.proxy.Socks5ProxyHandler
import us.myles.ViaVersion.exception.CancelCodecException
import java.net.SocketAddress
import java.nio.channels.ClosedChannelException
class MinecraftHandler(
val data: ConnectionData,
@ -44,6 +45,7 @@ class MinecraftHandler(
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
if (cause is CancelCodecException) return
if (cause is ClosedChannelException) return
mcLogger.debug("Exception: ", cause)
disconnect("Exception: $cause")
}

View File

@ -19,6 +19,7 @@ import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.handler.timeout.ReadTimeoutHandler
import io.netty.resolver.NoopAddressResolverGroup
import io.netty.util.concurrent.Future
import us.myles.ViaVersion.api.protocol.ProtocolVersion
import us.myles.ViaVersion.packets.State
@ -35,6 +36,7 @@ object ProtocolDetector {
try {
val ch: ChannelFuture = Bootstrap()
.group(childLoop)
.resolver(NoopAddressResolverGroup.INSTANCE)
.channelFactory(channelSocketFactory(childLoop))
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.IP_TOS, 0x18)

View File

@ -11,6 +11,7 @@ import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelOption
import io.netty.channel.socket.SocketChannel
import io.netty.resolver.NoopAddressResolverGroup
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -29,6 +30,7 @@ private fun createBackChannel(handler: MinecraftHandler, socketAddr: InetSocketA
.option(ChannelOption.IP_TOS, 0x18)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) // We need to show the error before the client timeout
.resolver(NoopAddressResolverGroup.INSTANCE)
.connect(socketAddr)
.addListener(ChannelFutureListener {
if (it.isSuccess) {
@ -50,8 +52,7 @@ private fun createBackChannel(handler: MinecraftHandler, socketAddr: InetSocketA
private fun tryBackAddress(
handler: MinecraftHandler,
iterator: Iterator<InetAddress>,
port: Int,
iterator: Iterator<InetSocketAddress>,
state: State,
success: () -> Unit,
) {
@ -60,13 +61,13 @@ private fun tryBackAddress(
// We're in the event loop
handler.disconnect("Couldn't connect: $e")
} else if (handler.data.frontChannel.isActive) {
tryBackAddress(handler, iterator, port, state, success)
tryBackAddress(handler, iterator, state, success)
}
}
try {
val socketAddr = InetSocketAddress(iterator.next(), port)
val socketAddr = iterator.next()
if (checkLocalAddress(socketAddr.address)
if ((socketAddr.address != null && checkLocalAddress(socketAddr.address))
|| matchesAddress(socketAddr, VIAaaSConfig.blockedBackAddresses)
|| !matchesAddress(socketAddr, VIAaaSConfig.allowedBackAddresses)
) {
@ -93,14 +94,21 @@ fun connectBack(handler: MinecraftHandler, address: String, port: Int, state: St
try {
val srvResolved = resolveSrv(address, port)
val iterator = InetAddress.getAllByName(srvResolved.first)
.groupBy { it is Inet4Address }
.toSortedMap() // I'm sorry, IPv4, but my true love is IPv6... We can still be friends though...
.map { it.value.random() }
.iterator()
val removedEndDot = srvResolved.first.replace(Regex("\\.$"), "")
val iterator =
if (!removedEndDot.endsWith(".onion")) {
InetAddress.getAllByName(srvResolved.first)
.groupBy { it is Inet4Address }
.toSortedMap() // I'm sorry, IPv4, but my true love is IPv6... We can still be friends though...
.map { InetSocketAddress(it.value.random(), srvResolved.second) }
.iterator()
} else {
listOf(InetSocketAddress.createUnresolved(removedEndDot, srvResolved.second)).iterator()
}
if (!iterator.hasNext()) throw IllegalArgumentException("Hostname has no IP address")
tryBackAddress(handler, iterator, srvResolved.second, state, success)
tryBackAddress(handler, iterator, state, success)
} catch (e: Exception) {
handler.data.frontChannel.eventLoop().submit {
handler.disconnect("Couldn't connect: $e")