From 4ce8bcc51148ba987a3be71f1707b57acbf7d11d Mon Sep 17 00:00:00 2001 From: creeper123123321 <7974274+creeper123123321@users.noreply.github.com> Date: Fri, 2 Jul 2021 20:46:15 -0300 Subject: [PATCH] protocol cache expiration, fix dns blocking thread, fix 1.8 fallback --- .../com/viaversion/aas/handler/BackEndInit.kt | 7 +- .../kotlin/com/viaversion/aas/handler/Util.kt | 7 +- .../handler/autoprotocol/ProtocolDetector.kt | 82 +++++++++++-------- .../com/viaversion/aas/handler/state/Util.kt | 39 +++++---- 4 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/main/kotlin/com/viaversion/aas/handler/BackEndInit.kt b/src/main/kotlin/com/viaversion/aas/handler/BackEndInit.kt index a2088dd..a65577b 100644 --- a/src/main/kotlin/com/viaversion/aas/handler/BackEndInit.kt +++ b/src/main/kotlin/com/viaversion/aas/handler/BackEndInit.kt @@ -7,13 +7,16 @@ import com.viaversion.viaversion.protocol.ProtocolPipelineImpl import io.netty.channel.Channel import io.netty.channel.ChannelInitializer import io.netty.handler.timeout.ReadTimeoutHandler +import java.net.InetSocketAddress +import java.net.URI import java.util.concurrent.TimeUnit -class BackEndInit(val connectionData: ConnectionData) : ChannelInitializer() { +class BackEndInit(val connectionData: ConnectionData, val proxyUri: URI?, val proxyAddress: InetSocketAddress?) : + ChannelInitializer() { override fun initChannel(ch: Channel) { val user = UserConnectionImpl(ch, true) ProtocolPipelineImpl(user) - ch.pipeline().also { addProxyHandler(it) } + ch.pipeline().also { addProxyHandler(it, proxyUri, proxyAddress) } // "crypto" .addLast("frame", FrameCodec()) // compress diff --git a/src/main/kotlin/com/viaversion/aas/handler/Util.kt b/src/main/kotlin/com/viaversion/aas/handler/Util.kt index 15a48c3..d62e177 100644 --- a/src/main/kotlin/com/viaversion/aas/handler/Util.kt +++ b/src/main/kotlin/com/viaversion/aas/handler/Util.kt @@ -1,8 +1,6 @@ package com.viaversion.aas.handler -import com.viaversion.aas.AspirinServer import com.viaversion.aas.codec.packet.Packet -import com.viaversion.aas.config.VIAaaSConfig import com.viaversion.aas.readRemainingBytes import com.viaversion.aas.send import com.viaversion.viaversion.api.protocol.version.ProtocolVersion @@ -14,6 +12,7 @@ import io.netty.handler.proxy.HttpProxyHandler import io.netty.handler.proxy.Socks4ProxyHandler import io.netty.handler.proxy.Socks5ProxyHandler import java.net.InetSocketAddress +import java.net.URI fun forward(handler: MinecraftHandler, packet: Packet, flush: Boolean = false) { send(handler.other!!, packet, flush) @@ -21,10 +20,8 @@ fun forward(handler: MinecraftHandler, packet: Packet, flush: Boolean = false) { fun is17(handler: MinecraftHandler) = handler.data.frontVer!! <= ProtocolVersion.v1_7_6.version -fun addProxyHandler(pipe: ChannelPipeline) { - val proxyUri = VIAaaSConfig.backendProxy +fun addProxyHandler(pipe: ChannelPipeline, proxyUri: URI?, socket: InetSocketAddress?) { if (proxyUri != null) { - val socket = InetSocketAddress(AspirinServer.dnsResolver.resolve(proxyUri.host).get(), proxyUri.port) val user = proxyUri.userInfo?.substringBefore(':') val pass = proxyUri.userInfo?.substringAfter(':') val handler = when (proxyUri.scheme) { diff --git a/src/main/kotlin/com/viaversion/aas/handler/autoprotocol/ProtocolDetector.kt b/src/main/kotlin/com/viaversion/aas/handler/autoprotocol/ProtocolDetector.kt index 4b6ec6d..d6dc132 100644 --- a/src/main/kotlin/com/viaversion/aas/handler/autoprotocol/ProtocolDetector.kt +++ b/src/main/kotlin/com/viaversion/aas/handler/autoprotocol/ProtocolDetector.kt @@ -8,12 +8,14 @@ import com.viaversion.aas.codec.FrameCodec import com.viaversion.aas.codec.MinecraftCodec import com.viaversion.aas.codec.packet.handshake.Handshake import com.viaversion.aas.codec.packet.status.StatusRequest +import com.viaversion.aas.config.VIAaaSConfig import com.viaversion.aas.handler.ConnectionData import com.viaversion.aas.handler.MinecraftHandler import com.viaversion.aas.handler.addProxyHandler import com.viaversion.aas.send import com.viaversion.viaversion.api.protocol.packet.State import com.viaversion.viaversion.api.protocol.version.ProtocolVersion +import io.ktor.server.netty.* import io.netty.bootstrap.Bootstrap import io.netty.channel.Channel import io.netty.channel.ChannelFutureListener @@ -21,52 +23,60 @@ import io.netty.channel.ChannelInitializer import io.netty.channel.ChannelOption import io.netty.handler.timeout.ReadTimeoutHandler import io.netty.resolver.NoopAddressResolverGroup +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import java.net.InetSocketAddress import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit object ProtocolDetector { private val SERVER_VER = CacheBuilder.newBuilder() - .expireAfterAccess(30, TimeUnit.SECONDS) + .expireAfterWrite(30, TimeUnit.SECONDS) .build>(CacheLoader.from { address -> val future = CompletableFuture() - try { - val ch = Bootstrap() - .group(AspirinServer.childLoop) - .resolver(NoopAddressResolverGroup.INSTANCE) - .channelFactory(channelSocketFactory(AspirinServer.childLoop)) - .option(ChannelOption.TCP_NODELAY, true) - .option(ChannelOption.IP_TOS, 0x18) - .handler(object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - val data = ConnectionData( - channel, - state = ProtocolDetectionState(future), - frontVer = -1 - ) - channel.pipeline().also { addProxyHandler(it) } - .addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) - .addLast("frame", FrameCodec()) - .addLast("mc", MinecraftCodec()) - .addLast("handler", MinecraftHandler(data, frontEnd = false)) + GlobalScope.launch { + try { + val proxyUri = VIAaaSConfig.backendProxy + val proxySocket = if (proxyUri == null) null else { + InetSocketAddress(AspirinServer.dnsResolver.resolve(proxyUri.host).suspendAwait(), proxyUri.port) + } + val ch = Bootstrap() + .group(AspirinServer.childLoop) + .resolver(NoopAddressResolverGroup.INSTANCE) + .channelFactory(channelSocketFactory(AspirinServer.childLoop)) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.IP_TOS, 0x18) + .handler(object : ChannelInitializer() { + override fun initChannel(channel: Channel) { + val data = ConnectionData( + channel, + state = ProtocolDetectionState(future), + frontVer = -1 + ) + channel.pipeline().also { addProxyHandler(it, proxyUri, proxySocket) } + .addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) + .addLast("frame", FrameCodec()) + .addLast("mc", MinecraftCodec()) + .addLast("handler", MinecraftHandler(data, frontEnd = false)) + } + }) + .connect(address!!) + ch.addListener(ChannelFutureListener { + if (!it.isSuccess) { + future.completeExceptionally(it.cause()) + } else { + val handshake = Handshake() + handshake.address = address.hostString + handshake.port = address.port + handshake.protocolId = -1 + handshake.nextState = State.STATUS + send(ch.channel(), handshake) + send(ch.channel(), StatusRequest(), flush = true) } }) - .connect(address!!) - ch.addListener(ChannelFutureListener { - if (!it.isSuccess) { - future.completeExceptionally(it.cause()) - } else { - val handshake = Handshake() - handshake.address = address.hostString - handshake.port = address.port - handshake.protocolId = -1 - handshake.nextState = State.STATUS - send(ch.channel(), handshake) - send(ch.channel(), StatusRequest(), flush = true) - } - }) - } catch (throwable: Throwable) { - future.completeExceptionally(throwable) + } catch (throwable: Throwable) { + future.completeExceptionally(throwable) + } } future }) diff --git a/src/main/kotlin/com/viaversion/aas/handler/state/Util.kt b/src/main/kotlin/com/viaversion/aas/handler/state/Util.kt index 1c9faa4..4b14954 100644 --- a/src/main/kotlin/com/viaversion/aas/handler/state/Util.kt +++ b/src/main/kotlin/com/viaversion/aas/handler/state/Util.kt @@ -19,19 +19,22 @@ import io.netty.channel.socket.SocketChannel import io.netty.handler.proxy.ProxyHandler import io.netty.resolver.NoopAddressResolverGroup import kotlinx.coroutines.future.await -import kotlinx.coroutines.withTimeoutOrNull +import kotlinx.coroutines.withTimeout import java.net.Inet4Address import java.net.InetSocketAddress +import java.net.URI private suspend fun createBackChannel( handler: MinecraftHandler, socketAddr: InetSocketAddress, state: State, - extraData: String? + extraData: String?, + proxyUri: URI?, + proxyAddress: InetSocketAddress? ): Channel { val loop = handler.data.frontChannel.eventLoop() val channel = Bootstrap() - .handler(BackEndInit(handler.data)) + .handler(BackEndInit(handler.data, proxyUri, proxyAddress)) .channelFactory(channelSocketFactory(loop.parent())) .group(loop) .option(ChannelOption.WRITE_BUFFER_WATER_MARK, AspirinServer.bufferWaterMark) @@ -64,23 +67,24 @@ private suspend fun createBackChannel( private suspend fun autoDetectVersion(handler: MinecraftHandler, socketAddr: InetSocketAddress) { if (handler.data.backServerVer == -2) { // Auto + var detectedProtocol: ProtocolVersion? = null try { - val detectedProtocol = withTimeoutOrNull(10_000) { + detectedProtocol = withTimeout(10_000) { ProtocolDetector.detectVersion(socketAddr).await() } - - if (detectedProtocol != null - && detectedProtocol.version !in arrayOf(-1, -2) - && ProtocolVersion.isRegistered(detectedProtocol.version) - ) { - handler.data.backServerVer = detectedProtocol.version - } else { - handler.data.backServerVer = 47 // fallback 1.8 - } } catch (e: Exception) { - mcLogger.warn("Failed to auto-detect version for $socketAddr: $e") + mcLogger.warn("Failed to detect version of $socketAddr: $e") mcLogger.debug("Stacktrace: ", e) } + + if (detectedProtocol != null + && detectedProtocol.version !in arrayOf(-1, -2) + && ProtocolVersion.isRegistered(detectedProtocol.version) + ) { + handler.data.backServerVer = detectedProtocol.version + } else { + handler.data.backServerVer = 47 // fallback 1.8 + } } } @@ -101,7 +105,12 @@ private suspend fun tryBackAddresses( throw StacklessException("Not allowed") } - createBackChannel(handler, socketAddr, state, extraData) + val proxyUri = VIAaaSConfig.backendProxy + val proxySocket = if (proxyUri == null) null else { + InetSocketAddress(AspirinServer.dnsResolver.resolve(proxyUri.host).suspendAwait(), proxyUri.port) + } + + createBackChannel(handler, socketAddr, state, extraData, proxyUri, proxySocket) return // Finally it worked! } catch (e: Exception) { latestException = e