protocol cache expiration, fix dns blocking thread, fix 1.8 fallback

This commit is contained in:
creeper123123321 2021-07-02 20:46:15 -03:00
parent 942908341a
commit 4ce8bcc511
4 changed files with 77 additions and 58 deletions

View File

@ -7,13 +7,16 @@ import com.viaversion.viaversion.protocol.ProtocolPipelineImpl
import io.netty.channel.Channel import io.netty.channel.Channel
import io.netty.channel.ChannelInitializer import io.netty.channel.ChannelInitializer
import io.netty.handler.timeout.ReadTimeoutHandler import io.netty.handler.timeout.ReadTimeoutHandler
import java.net.InetSocketAddress
import java.net.URI
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class BackEndInit(val connectionData: ConnectionData) : ChannelInitializer<Channel>() { class BackEndInit(val connectionData: ConnectionData, val proxyUri: URI?, val proxyAddress: InetSocketAddress?) :
ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) { override fun initChannel(ch: Channel) {
val user = UserConnectionImpl(ch, true) val user = UserConnectionImpl(ch, true)
ProtocolPipelineImpl(user) ProtocolPipelineImpl(user)
ch.pipeline().also { addProxyHandler(it) } ch.pipeline().also { addProxyHandler(it, proxyUri, proxyAddress) }
// "crypto" // "crypto"
.addLast("frame", FrameCodec()) .addLast("frame", FrameCodec())
// compress // compress

View File

@ -1,8 +1,6 @@
package com.viaversion.aas.handler package com.viaversion.aas.handler
import com.viaversion.aas.AspirinServer
import com.viaversion.aas.codec.packet.Packet import com.viaversion.aas.codec.packet.Packet
import com.viaversion.aas.config.VIAaaSConfig
import com.viaversion.aas.readRemainingBytes import com.viaversion.aas.readRemainingBytes
import com.viaversion.aas.send import com.viaversion.aas.send
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion 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.Socks4ProxyHandler
import io.netty.handler.proxy.Socks5ProxyHandler import io.netty.handler.proxy.Socks5ProxyHandler
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.URI
fun forward(handler: MinecraftHandler, packet: Packet, flush: Boolean = false) { fun forward(handler: MinecraftHandler, packet: Packet, flush: Boolean = false) {
send(handler.other!!, packet, flush) 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 is17(handler: MinecraftHandler) = handler.data.frontVer!! <= ProtocolVersion.v1_7_6.version
fun addProxyHandler(pipe: ChannelPipeline) { fun addProxyHandler(pipe: ChannelPipeline, proxyUri: URI?, socket: InetSocketAddress?) {
val proxyUri = VIAaaSConfig.backendProxy
if (proxyUri != null) { if (proxyUri != null) {
val socket = InetSocketAddress(AspirinServer.dnsResolver.resolve(proxyUri.host).get(), proxyUri.port)
val user = proxyUri.userInfo?.substringBefore(':') val user = proxyUri.userInfo?.substringBefore(':')
val pass = proxyUri.userInfo?.substringAfter(':') val pass = proxyUri.userInfo?.substringAfter(':')
val handler = when (proxyUri.scheme) { val handler = when (proxyUri.scheme) {

View File

@ -8,12 +8,14 @@ import com.viaversion.aas.codec.FrameCodec
import com.viaversion.aas.codec.MinecraftCodec import com.viaversion.aas.codec.MinecraftCodec
import com.viaversion.aas.codec.packet.handshake.Handshake import com.viaversion.aas.codec.packet.handshake.Handshake
import com.viaversion.aas.codec.packet.status.StatusRequest 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.ConnectionData
import com.viaversion.aas.handler.MinecraftHandler import com.viaversion.aas.handler.MinecraftHandler
import com.viaversion.aas.handler.addProxyHandler import com.viaversion.aas.handler.addProxyHandler
import com.viaversion.aas.send import com.viaversion.aas.send
import com.viaversion.viaversion.api.protocol.packet.State import com.viaversion.viaversion.api.protocol.packet.State
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
import io.ktor.server.netty.*
import io.netty.bootstrap.Bootstrap import io.netty.bootstrap.Bootstrap
import io.netty.channel.Channel import io.netty.channel.Channel
import io.netty.channel.ChannelFutureListener import io.netty.channel.ChannelFutureListener
@ -21,52 +23,60 @@ import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.netty.handler.timeout.ReadTimeoutHandler import io.netty.handler.timeout.ReadTimeoutHandler
import io.netty.resolver.NoopAddressResolverGroup import io.netty.resolver.NoopAddressResolverGroup
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
object ProtocolDetector { object ProtocolDetector {
private val SERVER_VER = CacheBuilder.newBuilder() private val SERVER_VER = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS) .expireAfterWrite(30, TimeUnit.SECONDS)
.build<InetSocketAddress, CompletableFuture<ProtocolVersion>>(CacheLoader.from { address -> .build<InetSocketAddress, CompletableFuture<ProtocolVersion>>(CacheLoader.from { address ->
val future = CompletableFuture<ProtocolVersion>() val future = CompletableFuture<ProtocolVersion>()
try { GlobalScope.launch {
val ch = Bootstrap() try {
.group(AspirinServer.childLoop) val proxyUri = VIAaaSConfig.backendProxy
.resolver(NoopAddressResolverGroup.INSTANCE) val proxySocket = if (proxyUri == null) null else {
.channelFactory(channelSocketFactory(AspirinServer.childLoop)) InetSocketAddress(AspirinServer.dnsResolver.resolve(proxyUri.host).suspendAwait(), proxyUri.port)
.option(ChannelOption.TCP_NODELAY, true) }
.option(ChannelOption.IP_TOS, 0x18) val ch = Bootstrap()
.handler(object : ChannelInitializer<Channel>() { .group(AspirinServer.childLoop)
override fun initChannel(channel: Channel) { .resolver(NoopAddressResolverGroup.INSTANCE)
val data = ConnectionData( .channelFactory(channelSocketFactory(AspirinServer.childLoop))
channel, .option(ChannelOption.TCP_NODELAY, true)
state = ProtocolDetectionState(future), .option(ChannelOption.IP_TOS, 0x18)
frontVer = -1 .handler(object : ChannelInitializer<Channel>() {
) override fun initChannel(channel: Channel) {
channel.pipeline().also { addProxyHandler(it) } val data = ConnectionData(
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) channel,
.addLast("frame", FrameCodec()) state = ProtocolDetectionState(future),
.addLast("mc", MinecraftCodec()) frontVer = -1
.addLast("handler", MinecraftHandler(data, frontEnd = false)) )
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!!) } catch (throwable: Throwable) {
ch.addListener(ChannelFutureListener { future.completeExceptionally(throwable)
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)
} }
future future
}) })

View File

@ -19,19 +19,22 @@ import io.netty.channel.socket.SocketChannel
import io.netty.handler.proxy.ProxyHandler import io.netty.handler.proxy.ProxyHandler
import io.netty.resolver.NoopAddressResolverGroup import io.netty.resolver.NoopAddressResolverGroup
import kotlinx.coroutines.future.await import kotlinx.coroutines.future.await
import kotlinx.coroutines.withTimeoutOrNull import kotlinx.coroutines.withTimeout
import java.net.Inet4Address import java.net.Inet4Address
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.URI
private suspend fun createBackChannel( private suspend fun createBackChannel(
handler: MinecraftHandler, handler: MinecraftHandler,
socketAddr: InetSocketAddress, socketAddr: InetSocketAddress,
state: State, state: State,
extraData: String? extraData: String?,
proxyUri: URI?,
proxyAddress: InetSocketAddress?
): Channel { ): Channel {
val loop = handler.data.frontChannel.eventLoop() val loop = handler.data.frontChannel.eventLoop()
val channel = Bootstrap() val channel = Bootstrap()
.handler(BackEndInit(handler.data)) .handler(BackEndInit(handler.data, proxyUri, proxyAddress))
.channelFactory(channelSocketFactory(loop.parent())) .channelFactory(channelSocketFactory(loop.parent()))
.group(loop) .group(loop)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, AspirinServer.bufferWaterMark) .option(ChannelOption.WRITE_BUFFER_WATER_MARK, AspirinServer.bufferWaterMark)
@ -64,23 +67,24 @@ private suspend fun createBackChannel(
private suspend fun autoDetectVersion(handler: MinecraftHandler, socketAddr: InetSocketAddress) { private suspend fun autoDetectVersion(handler: MinecraftHandler, socketAddr: InetSocketAddress) {
if (handler.data.backServerVer == -2) { // Auto if (handler.data.backServerVer == -2) { // Auto
var detectedProtocol: ProtocolVersion? = null
try { try {
val detectedProtocol = withTimeoutOrNull(10_000) { detectedProtocol = withTimeout(10_000) {
ProtocolDetector.detectVersion(socketAddr).await() 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) { } 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) 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") 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! return // Finally it worked!
} catch (e: Exception) { } catch (e: Exception) {
latestException = e latestException = e