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.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<Channel>() {
class BackEndInit(val connectionData: ConnectionData, val proxyUri: URI?, val proxyAddress: InetSocketAddress?) :
ChannelInitializer<Channel>() {
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

View File

@ -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) {

View File

@ -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<InetSocketAddress, CompletableFuture<ProtocolVersion>>(CacheLoader.from { address ->
val future = CompletableFuture<ProtocolVersion>()
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<Channel>() {
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<Channel>() {
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
})

View File

@ -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