From 1638270bd8e96374b95478a6640a66961c03dc62 Mon Sep 17 00:00:00 2001 From: creeper123123321 <7974274+creeper123123321@users.noreply.github.com> Date: Sat, 13 Mar 2021 12:32:08 -0300 Subject: [PATCH] move timeouthandler, redirect stdout, kick packet, websocket msg change --- build.gradle.kts | 2 + .../github/creeper123123321/viaaas/Util.kt | 3 +- .../github/creeper123123321/viaaas/VIAaaS.kt | 5 +++ .../viaaas/handler/BackEndInit.kt | 5 ++- .../viaaas/handler/FrontEndInit.kt | 4 +- .../viaaas/handler/state/PlayState.kt | 8 +++- .../viaaas/packet/PacketRegistry.kt | 12 ++++++ .../viaaas/packet/play/Kick.kt | 16 +++++++ .../creeper123123321/viaaas/web/ViaWebApp.kt | 1 - .../creeper123123321/viaaas/web/WebClient.kt | 13 ++++-- .../viaaas/web/WebDashboardServer.kt | 43 ++++++++++--------- .../creeper123123321/viaaas/web/WebLogin.kt | 10 ++--- 12 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 src/main/kotlin/com/github/creeper123123321/viaaas/packet/play/Kick.kt diff --git a/build.gradle.kts b/build.gradle.kts index 2aa9493..04afeab 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,7 +54,9 @@ dependencies { val log4jVer = "2.14.0" implementation("org.apache.logging.log4j:log4j-core:$log4jVer") + implementation("org.apache.logging.log4j:log4j-iostreams:$log4jVer") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVer") + implementation("org.apache.logging.log4j:log4j-jul:$log4jVer") implementation("org.slf4j:slf4j-api:1.7.30") implementation("net.minecrell:terminalconsoleappender:1.2.0") implementation("org.jline:jline-terminal-jansi:3.19.0") diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/Util.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/Util.kt index 19cacf1..4a02463 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/Util.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/Util.kt @@ -8,6 +8,7 @@ import com.google.gson.JsonObject import io.ktor.client.request.* import io.netty.buffer.ByteBuf import io.netty.channel.Channel +import io.netty.channel.ChannelFutureListener import io.netty.handler.codec.DecoderException import org.slf4j.LoggerFactory import java.math.BigInteger @@ -143,7 +144,7 @@ fun send(ch: Channel, obj: Any, flush: Boolean = false) { } fun writeFlushClose(ch: Channel, obj: Any) { - ch.writeAndFlush(obj).addListener { ch.close() } + ch.writeAndFlush(obj).addListener(ChannelFutureListener.CLOSE) } val secureRandom = if (VIAaaSConfig.useStrongRandom) SecureRandom.getInstanceStrong() else SecureRandom() diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/VIAaaS.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/VIAaaS.kt index 0d6c6be..2a8e001 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/VIAaaS.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/VIAaaS.kt @@ -34,6 +34,8 @@ import io.netty.channel.socket.SocketChannel import io.netty.channel.socket.nio.NioServerSocketChannel import io.netty.channel.socket.nio.NioSocketChannel import io.netty.util.concurrent.Future +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.io.IoBuilder import us.myles.ViaVersion.ViaManager import us.myles.ViaVersion.api.Via import us.myles.ViaVersion.api.data.MappingDataLoader @@ -97,6 +99,9 @@ fun main(args: Array) { if (System.getProperty("io.netty.allocator.maxOrder") == null) { System.setProperty("io.netty.allocator.maxOrder", "9") } + // Also stolen from Velocity + System.setOut(IoBuilder.forLogger("STDOUT").setLevel(Level.INFO).buildPrintStream()); + System.setErr(IoBuilder.forLogger("STDERR").setLevel(Level.ERROR).buildPrintStream()); File("config/https.jks").apply { parentFile.mkdirs() diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/handler/BackEndInit.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/handler/BackEndInit.kt index 3c30d12..9987dbe 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/handler/BackEndInit.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/handler/BackEndInit.kt @@ -14,11 +14,12 @@ class BackEndInit(val connectionData: ConnectionData) : ChannelInitializer() { override fun initChannel(ch: Channel) { ch.pipeline() - .addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) // "crypto" .addLast("frame", FrameCodec()) // "compress" .addLast("flow-handler", FlowControlHandler()) .addLast("mc", MinecraftCodec()) + .addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) .addLast("handler", MinecraftHandler(ConnectionData(frontChannel = ch), frontEnd = true)) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/handler/state/PlayState.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/handler/state/PlayState.kt index 5cc936b..e65bd57 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/handler/state/PlayState.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/handler/state/PlayState.kt @@ -6,8 +6,11 @@ import com.github.creeper123123321.viaaas.handler.forward import com.github.creeper123123321.viaaas.handler.is1_7 import com.github.creeper123123321.viaaas.packet.Packet import com.github.creeper123123321.viaaas.packet.UnknownPacket +import com.github.creeper123123321.viaaas.packet.play.Kick import com.github.creeper123123321.viaaas.packet.play.PluginMessage import com.github.creeper123123321.viaaas.readableToByteArray +import com.github.creeper123123321.viaaas.writeFlushClose +import com.google.gson.JsonPrimitive import io.netty.buffer.ByteBufAllocator import io.netty.buffer.Unpooled import io.netty.channel.ChannelHandlerContext @@ -22,7 +25,7 @@ object PlayState : MinecraftConnectionState { override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) { when { packet is UnknownPacket && (packet.id !in 0..127) -> throw IllegalArgumentException("Invalid packet id!") - packet is PluginMessage -> modifyPluginMessage(handler, packet) + packet is PluginMessage && !handler.frontEnd -> modifyPluginMessage(handler, packet) } forward(handler, packet) } @@ -58,6 +61,7 @@ object PlayState : MinecraftConnectionState { override fun disconnect(handler: MinecraftHandler, msg: String) { super.disconnect(handler, msg) - handler.data.frontChannel.close() + writeFlushClose(handler.data.frontChannel, + Kick().also { it.msg = JsonPrimitive("[VIAaaS] $msg").toString() }) } } \ No newline at end of file diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/packet/PacketRegistry.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/packet/PacketRegistry.kt index fa9585d..82e109d 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/packet/PacketRegistry.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/packet/PacketRegistry.kt @@ -2,6 +2,7 @@ package com.github.creeper123123321.viaaas.packet import com.github.creeper123123321.viaaas.packet.handshake.Handshake import com.github.creeper123123321.viaaas.packet.login.* +import com.github.creeper123123321.viaaas.packet.play.Kick import com.github.creeper123123321.viaaas.packet.play.PluginMessage import com.github.creeper123123321.viaaas.packet.status.StatusPing import com.github.creeper123123321.viaaas.packet.status.StatusPong @@ -32,6 +33,17 @@ object PacketRegistry { register(Range.all(), State.STATUS, 1, true, ::StatusPing) register(Range.all(), State.STATUS, 0, false, ::StatusResponse) register(Range.all(), State.STATUS, 1, false, ::StatusPong) + register( + ::Kick, State.PLAY, false, mapOf( + Range.closed(ProtocolVersion.v1_7_1.version, ProtocolVersion.v1_8.version) to 0x40, + Range.closed(ProtocolVersion.v1_9.version, ProtocolVersion.v1_12_2.version) to 0x1A, + Range.closed(ProtocolVersion.v1_13.version, ProtocolVersion.v1_13_2.version) to 0x1B, + Range.closed(ProtocolVersion.v1_14.version, ProtocolVersion.v1_14_4.version) to 0x1A, + Range.closed(ProtocolVersion.v1_15.version, ProtocolVersion.v1_15_2.version) to 0x1B, + Range.closed(ProtocolVersion.v1_16.version, ProtocolVersion.v1_16_1.version) to 0x1A, + Range.closed(ProtocolVersion.v1_16_2.version, ProtocolVersion.v1_16_4.version) to 0x19 + ) + ) register( ::PluginMessage, State.PLAY, true, mapOf( Range.closed(ProtocolVersion.v1_7_1.version, ProtocolVersion.v1_8.version) to 0x17, diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/packet/play/Kick.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/packet/play/Kick.kt new file mode 100644 index 0000000..7d6f6ae --- /dev/null +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/packet/play/Kick.kt @@ -0,0 +1,16 @@ +package com.github.creeper123123321.viaaas.packet.play + +import com.github.creeper123123321.viaaas.packet.Packet +import io.netty.buffer.ByteBuf +import us.myles.ViaVersion.api.type.Type + +class Kick : Packet { + lateinit var msg: String + override fun decode(byteBuf: ByteBuf, protocolVersion: Int) { + msg = Type.STRING.read(byteBuf) + } + + override fun encode(byteBuf: ByteBuf, protocolVersion: Int) { + Type.STRING.write(byteBuf, msg) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/web/ViaWebApp.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/web/ViaWebApp.kt index 760a6fb..8d13a96 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/web/ViaWebApp.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/web/ViaWebApp.kt @@ -43,7 +43,6 @@ class ViaWebApp { } } catch (ignored: ClosedChannelException) { } catch (e: Exception) { - webLogger.info("${call.request.local.remoteHost} (O: ${call.request.origin.remoteHost}) exception: $e") viaWebServer.onException(this, e) this.close(CloseReason(CloseReason.Codes.INTERNAL_ERROR, "INTERNAL ERROR")) } finally { diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebClient.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebClient.kt index 37e74d3..ddafc97 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebClient.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebClient.kt @@ -1,23 +1,30 @@ package com.github.creeper123123321.viaaas.web import com.github.creeper123123321.viaaas.config.VIAaaSConfig +import com.google.common.collect.Sets import com.google.common.util.concurrent.RateLimiter +import io.ktor.features.* import io.ktor.websocket.* import java.util.* import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicInteger data class WebClient( val server: WebDashboardServer, val ws: WebSocketServerSession, val state: WebState, ) { - val listenedIds: MutableSet = Collections.newSetFromMap(ConcurrentHashMap()) + object IdGen { + val atInt = AtomicInteger() + fun next() = atInt.getAndAdd(1) + } + val id = "${ws.call.request.local.host}(${ws.call.request.origin.host})-${IdGen.next()}" + val listenedIds: MutableSet = Sets.newConcurrentHashSet() val rateLimiter = RateLimiter.create(VIAaaSConfig.rateLimitWs) fun listenId(uuid: UUID): Boolean { if (listenedIds.size >= VIAaaSConfig.listeningWsLimit) return false // This is getting insane - server.listeners.computeIfAbsent(uuid) { Collections.newSetFromMap(ConcurrentHashMap()) } - .add(this) + server.listeners.computeIfAbsent(uuid) { Sets.newConcurrentHashSet() }.add(this) listenedIds.add(uuid) return true } diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebDashboardServer.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebDashboardServer.kt index c5b5f97..d4c2c95 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebDashboardServer.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebDashboardServer.kt @@ -3,10 +3,12 @@ package com.github.creeper123123321.viaaas.web import com.github.creeper123123321.viaaas.httpClient import com.github.creeper123123321.viaaas.parseUndashedId import com.github.creeper123123321.viaaas.viaWebServer +import com.github.creeper123123321.viaaas.webLogger import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader import com.google.gson.JsonObject import io.ktor.client.request.* +import io.ktor.features.* import io.ktor.http.cio.websocket.* import io.ktor.websocket.* import kotlinx.coroutines.Dispatchers @@ -52,26 +54,24 @@ class WebDashboardServer { id: UUID, name: String, hash: String, address: SocketAddress, backAddress: SocketAddress ): CompletableFuture { - val future = viaWebServer.pendingSessionHashes.get(hash) - var sent = 0 - viaWebServer.listeners[id]?.forEach { - it.ws.send( - JsonObject().also { - it.addProperty("action", "session_hash_request") - it.addProperty("user", name) - it.addProperty("session_hash", hash) - it.addProperty("message", "Client is $address, backend is $backAddress") - }.toString() - ) - it.ws.flush() - sent++ - } - if (sent != 0) { + val future = pendingSessionHashes.get(hash) + if (listeners[id]?.isEmpty() != false) { + future.completeExceptionally(IllegalStateException("No browser listening")) + } else { + listeners[id]?.forEach { + it.ws.send( + JsonObject().also { + it.addProperty("action", "session_hash_request") + it.addProperty("user", name) + it.addProperty("session_hash", hash) + it.addProperty("message", "Client is $address, backend is $backAddress") + }.toString() + ) + it.ws.flush() + } Via.getPlatform().runSync({ future.completeExceptionally(TimeoutException("No response from browser")) }, 15 * 20) - } else { - future.completeExceptionally(IllegalStateException("No browser listening")) } return future } @@ -79,24 +79,27 @@ class WebDashboardServer { suspend fun connected(ws: WebSocketServerSession) { val loginState = WebLogin() val client = WebClient(this, ws, loginState) + webLogger.info("+ WS: ${client.id}") clients[ws] = client loginState.start(client) } - suspend fun onMessage(ws: WebSocketSession, msg: String) { + suspend fun onMessage(ws: WebSocketServerSession, msg: String) { val client = clients[ws]!! client.rateLimiter.acquire() client.state.onMessage(client, msg) } - suspend fun disconnected(ws: WebSocketSession) { + suspend fun disconnected(ws: WebSocketServerSession) { val client = clients[ws]!! + webLogger.info("- WS: ${client.id}") client.state.disconnected(client) clients.remove(ws) } - suspend fun onException(ws: WebSocketSession, exception: java.lang.Exception) { + suspend fun onException(ws: WebSocketServerSession, exception: Exception) { val client = clients[ws]!! + webLogger.info("WS Error: ${client.id} $exception") client.state.onException(client, exception) } } diff --git a/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebLogin.kt b/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebLogin.kt index cede50f..09d4377 100644 --- a/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebLogin.kt +++ b/src/main/kotlin/com/github/creeper123123321/viaaas/web/WebLogin.kt @@ -33,7 +33,7 @@ class WebLogin : WebState { | "username": "$username", "uuid": "$uuid", "token": "$token"}""".trimMargin() ) - webLogger.info("Token gen: ${webClient.ws.call.request.local.remoteHost} (O: ${webClient.ws.call.request.origin.remoteHost}): offline $username") + webLogger.info("Token gen: ${webClient.id}: offline $username $uuid") } "minecraft_id_login" -> { val username = obj.get("username").asString @@ -54,10 +54,10 @@ class WebLogin : WebState { | "username": "$mcIdUser", "uuid": "$uuid", "token": "$token"}""".trimMargin() ) - webLogger.info("Token gen: ${webClient.ws.call.request.local.remoteHost} (O: ${webClient.ws.call.request.origin.remoteHost}): $mcIdUser $uuid") + webLogger.info("Token gen: ${webClient.id}: $mcIdUser $uuid") } else { webClient.ws.send("""{"action": "login_result", "success": false}""") - webLogger.info("Token gen fail: ${webClient.ws.call.request.local.remoteHost} (O: ${webClient.ws.call.request.origin.remoteHost}): $username") + webLogger.info("Token gen fail: ${webClient.id}: $username") } } "listen_login_requests" -> { @@ -65,11 +65,11 @@ class WebLogin : WebState { val user = webClient.server.loginTokens.getIfPresent(token) if (user != null && webClient.listenId(user)) { webClient.ws.send("""{"action": "listen_login_requests_result", "token": "$token", "success": true, "user": "$user"}""") - webLogger.info("Listen: ${webClient.ws.call.request.local.remoteHost} (O: ${webClient.ws.call.request.origin.remoteHost}): $user") + webLogger.info("Listen: ${webClient.id}: $user") } else { webClient.server.loginTokens.invalidate(token) webClient.ws.send("""{"action": "listen_login_requests_result", "token": "$token", "success": false}""") - webLogger.info("Token fail: ${webClient.ws.call.request.local.remoteHost} (O: ${webClient.ws.call.request.origin.remoteHost})") + webLogger.info("Token fail: ${webClient.id}") } } "unlisten_login_requests" -> {