move timeouthandler, redirect stdout, kick packet, websocket msg change

This commit is contained in:
creeper123123321 2021-03-13 12:32:08 -03:00
parent 92166ecf5a
commit 1638270bd8
12 changed files with 86 additions and 36 deletions

View File

@ -54,7 +54,9 @@ dependencies {
val log4jVer = "2.14.0" val log4jVer = "2.14.0"
implementation("org.apache.logging.log4j:log4j-core:$log4jVer") 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-slf4j-impl:$log4jVer")
implementation("org.apache.logging.log4j:log4j-jul:$log4jVer")
implementation("org.slf4j:slf4j-api:1.7.30") implementation("org.slf4j:slf4j-api:1.7.30")
implementation("net.minecrell:terminalconsoleappender:1.2.0") implementation("net.minecrell:terminalconsoleappender:1.2.0")
implementation("org.jline:jline-terminal-jansi:3.19.0") implementation("org.jline:jline-terminal-jansi:3.19.0")

View File

@ -8,6 +8,7 @@ import com.google.gson.JsonObject
import io.ktor.client.request.* import io.ktor.client.request.*
import io.netty.buffer.ByteBuf import io.netty.buffer.ByteBuf
import io.netty.channel.Channel import io.netty.channel.Channel
import io.netty.channel.ChannelFutureListener
import io.netty.handler.codec.DecoderException import io.netty.handler.codec.DecoderException
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.math.BigInteger import java.math.BigInteger
@ -143,7 +144,7 @@ fun send(ch: Channel, obj: Any, flush: Boolean = false) {
} }
fun writeFlushClose(ch: Channel, obj: Any) { 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() val secureRandom = if (VIAaaSConfig.useStrongRandom) SecureRandom.getInstanceStrong() else SecureRandom()

View File

@ -34,6 +34,8 @@ import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.channel.socket.nio.NioSocketChannel import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.util.concurrent.Future 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.ViaManager
import us.myles.ViaVersion.api.Via import us.myles.ViaVersion.api.Via
import us.myles.ViaVersion.api.data.MappingDataLoader import us.myles.ViaVersion.api.data.MappingDataLoader
@ -97,6 +99,9 @@ fun main(args: Array<String>) {
if (System.getProperty("io.netty.allocator.maxOrder") == null) { if (System.getProperty("io.netty.allocator.maxOrder") == null) {
System.setProperty("io.netty.allocator.maxOrder", "9") 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 { File("config/https.jks").apply {
parentFile.mkdirs() parentFile.mkdirs()

View File

@ -14,11 +14,12 @@ class BackEndInit(val connectionData: ConnectionData) : ChannelInitializer<Chann
override fun initChannel(ch: Channel) { override fun initChannel(ch: Channel) {
val user = UserConnection(ch, true) val user = UserConnection(ch, true)
ProtocolPipeline(user) ProtocolPipeline(user)
ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) ch.pipeline()
// "crypto" // "crypto"
.addLast("frame", FrameCodec()) .addLast("frame", FrameCodec())
// compress // compress
.addLast("via-codec", ViaCodec(user)) .addLast("via-codec", ViaCodec(user))
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
.addLast("mc", MinecraftCodec()) .addLast("mc", MinecraftCodec())
.also { .also {
if (connectionData.viaBackServerVer == null) { if (connectionData.viaBackServerVer == null) {

View File

@ -11,12 +11,12 @@ import java.util.concurrent.TimeUnit
object FrontEndInit : ChannelInitializer<Channel>() { object FrontEndInit : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) { override fun initChannel(ch: Channel) {
ch.pipeline() ch.pipeline()
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
// "crypto" // "crypto"
.addLast("frame", FrameCodec()) .addLast("frame", FrameCodec())
// "compress" // "compress"
.addLast("flow-handler", FlowControlHandler()) .addLast("flow-handler", FlowControlHandler())
.addLast("mc", MinecraftCodec()) .addLast("mc", MinecraftCodec())
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
.addLast("handler", MinecraftHandler(ConnectionData(frontChannel = ch), frontEnd = true)) .addLast("handler", MinecraftHandler(ConnectionData(frontChannel = ch), frontEnd = true))
} }
} }

View File

@ -6,8 +6,11 @@ import com.github.creeper123123321.viaaas.handler.forward
import com.github.creeper123123321.viaaas.handler.is1_7 import com.github.creeper123123321.viaaas.handler.is1_7
import com.github.creeper123123321.viaaas.packet.Packet import com.github.creeper123123321.viaaas.packet.Packet
import com.github.creeper123123321.viaaas.packet.UnknownPacket 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.packet.play.PluginMessage
import com.github.creeper123123321.viaaas.readableToByteArray 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.ByteBufAllocator
import io.netty.buffer.Unpooled import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelHandlerContext
@ -22,7 +25,7 @@ object PlayState : MinecraftConnectionState {
override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) { override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) {
when { when {
packet is UnknownPacket && (packet.id !in 0..127) -> throw IllegalArgumentException("Invalid packet id!") 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) forward(handler, packet)
} }
@ -58,6 +61,7 @@ object PlayState : MinecraftConnectionState {
override fun disconnect(handler: MinecraftHandler, msg: String) { override fun disconnect(handler: MinecraftHandler, msg: String) {
super.disconnect(handler, msg) super.disconnect(handler, msg)
handler.data.frontChannel.close() writeFlushClose(handler.data.frontChannel,
Kick().also { it.msg = JsonPrimitive("[VIAaaS] $msg").toString() })
} }
} }

View File

@ -2,6 +2,7 @@ package com.github.creeper123123321.viaaas.packet
import com.github.creeper123123321.viaaas.packet.handshake.Handshake import com.github.creeper123123321.viaaas.packet.handshake.Handshake
import com.github.creeper123123321.viaaas.packet.login.* 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.play.PluginMessage
import com.github.creeper123123321.viaaas.packet.status.StatusPing import com.github.creeper123123321.viaaas.packet.status.StatusPing
import com.github.creeper123123321.viaaas.packet.status.StatusPong 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, 1, true, ::StatusPing)
register(Range.all(), State.STATUS, 0, false, ::StatusResponse) register(Range.all(), State.STATUS, 0, false, ::StatusResponse)
register(Range.all(), State.STATUS, 1, false, ::StatusPong) 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( register(
::PluginMessage, State.PLAY, true, mapOf( ::PluginMessage, State.PLAY, true, mapOf(
Range.closed(ProtocolVersion.v1_7_1.version, ProtocolVersion.v1_8.version) to 0x17, Range.closed(ProtocolVersion.v1_7_1.version, ProtocolVersion.v1_8.version) to 0x17,

View File

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

View File

@ -43,7 +43,6 @@ class ViaWebApp {
} }
} catch (ignored: ClosedChannelException) { } catch (ignored: ClosedChannelException) {
} catch (e: Exception) { } catch (e: Exception) {
webLogger.info("${call.request.local.remoteHost} (O: ${call.request.origin.remoteHost}) exception: $e")
viaWebServer.onException(this, e) viaWebServer.onException(this, e)
this.close(CloseReason(CloseReason.Codes.INTERNAL_ERROR, "INTERNAL ERROR")) this.close(CloseReason(CloseReason.Codes.INTERNAL_ERROR, "INTERNAL ERROR"))
} finally { } finally {

View File

@ -1,23 +1,30 @@
package com.github.creeper123123321.viaaas.web package com.github.creeper123123321.viaaas.web
import com.github.creeper123123321.viaaas.config.VIAaaSConfig import com.github.creeper123123321.viaaas.config.VIAaaSConfig
import com.google.common.collect.Sets
import com.google.common.util.concurrent.RateLimiter import com.google.common.util.concurrent.RateLimiter
import io.ktor.features.*
import io.ktor.websocket.* import io.ktor.websocket.*
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
data class WebClient( data class WebClient(
val server: WebDashboardServer, val server: WebDashboardServer,
val ws: WebSocketServerSession, val ws: WebSocketServerSession,
val state: WebState, val state: WebState,
) { ) {
val listenedIds: MutableSet<UUID> = 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<UUID> = Sets.newConcurrentHashSet()
val rateLimiter = RateLimiter.create(VIAaaSConfig.rateLimitWs) val rateLimiter = RateLimiter.create(VIAaaSConfig.rateLimitWs)
fun listenId(uuid: UUID): Boolean { fun listenId(uuid: UUID): Boolean {
if (listenedIds.size >= VIAaaSConfig.listeningWsLimit) return false // This is getting insane if (listenedIds.size >= VIAaaSConfig.listeningWsLimit) return false // This is getting insane
server.listeners.computeIfAbsent(uuid) { Collections.newSetFromMap(ConcurrentHashMap()) } server.listeners.computeIfAbsent(uuid) { Sets.newConcurrentHashSet() }.add(this)
.add(this)
listenedIds.add(uuid) listenedIds.add(uuid)
return true return true
} }

View File

@ -3,10 +3,12 @@ package com.github.creeper123123321.viaaas.web
import com.github.creeper123123321.viaaas.httpClient import com.github.creeper123123321.viaaas.httpClient
import com.github.creeper123123321.viaaas.parseUndashedId import com.github.creeper123123321.viaaas.parseUndashedId
import com.github.creeper123123321.viaaas.viaWebServer import com.github.creeper123123321.viaaas.viaWebServer
import com.github.creeper123123321.viaaas.webLogger
import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader import com.google.common.cache.CacheLoader
import com.google.gson.JsonObject import com.google.gson.JsonObject
import io.ktor.client.request.* import io.ktor.client.request.*
import io.ktor.features.*
import io.ktor.http.cio.websocket.* import io.ktor.http.cio.websocket.*
import io.ktor.websocket.* import io.ktor.websocket.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -52,9 +54,11 @@ class WebDashboardServer {
id: UUID, name: String, hash: String, id: UUID, name: String, hash: String,
address: SocketAddress, backAddress: SocketAddress address: SocketAddress, backAddress: SocketAddress
): CompletableFuture<Unit> { ): CompletableFuture<Unit> {
val future = viaWebServer.pendingSessionHashes.get(hash) val future = pendingSessionHashes.get(hash)
var sent = 0 if (listeners[id]?.isEmpty() != false) {
viaWebServer.listeners[id]?.forEach { future.completeExceptionally(IllegalStateException("No browser listening"))
} else {
listeners[id]?.forEach {
it.ws.send( it.ws.send(
JsonObject().also { JsonObject().also {
it.addProperty("action", "session_hash_request") it.addProperty("action", "session_hash_request")
@ -64,14 +68,10 @@ class WebDashboardServer {
}.toString() }.toString()
) )
it.ws.flush() it.ws.flush()
sent++
} }
if (sent != 0) {
Via.getPlatform().runSync({ Via.getPlatform().runSync({
future.completeExceptionally(TimeoutException("No response from browser")) future.completeExceptionally(TimeoutException("No response from browser"))
}, 15 * 20) }, 15 * 20)
} else {
future.completeExceptionally(IllegalStateException("No browser listening"))
} }
return future return future
} }
@ -79,24 +79,27 @@ class WebDashboardServer {
suspend fun connected(ws: WebSocketServerSession) { suspend fun connected(ws: WebSocketServerSession) {
val loginState = WebLogin() val loginState = WebLogin()
val client = WebClient(this, ws, loginState) val client = WebClient(this, ws, loginState)
webLogger.info("+ WS: ${client.id}")
clients[ws] = client clients[ws] = client
loginState.start(client) loginState.start(client)
} }
suspend fun onMessage(ws: WebSocketSession, msg: String) { suspend fun onMessage(ws: WebSocketServerSession, msg: String) {
val client = clients[ws]!! val client = clients[ws]!!
client.rateLimiter.acquire() client.rateLimiter.acquire()
client.state.onMessage(client, msg) client.state.onMessage(client, msg)
} }
suspend fun disconnected(ws: WebSocketSession) { suspend fun disconnected(ws: WebSocketServerSession) {
val client = clients[ws]!! val client = clients[ws]!!
webLogger.info("- WS: ${client.id}")
client.state.disconnected(client) client.state.disconnected(client)
clients.remove(ws) clients.remove(ws)
} }
suspend fun onException(ws: WebSocketSession, exception: java.lang.Exception) { suspend fun onException(ws: WebSocketServerSession, exception: Exception) {
val client = clients[ws]!! val client = clients[ws]!!
webLogger.info("WS Error: ${client.id} $exception")
client.state.onException(client, exception) client.state.onException(client, exception)
} }
} }

View File

@ -33,7 +33,7 @@ class WebLogin : WebState {
| "username": "$username", "uuid": "$uuid", "token": "$token"}""".trimMargin() | "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" -> { "minecraft_id_login" -> {
val username = obj.get("username").asString val username = obj.get("username").asString
@ -54,10 +54,10 @@ class WebLogin : WebState {
| "username": "$mcIdUser", "uuid": "$uuid", "token": "$token"}""".trimMargin() | "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 { } else {
webClient.ws.send("""{"action": "login_result", "success": false}""") 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" -> { "listen_login_requests" -> {
@ -65,11 +65,11 @@ class WebLogin : WebState {
val user = webClient.server.loginTokens.getIfPresent(token) val user = webClient.server.loginTokens.getIfPresent(token)
if (user != null && webClient.listenId(user)) { if (user != null && webClient.listenId(user)) {
webClient.ws.send("""{"action": "listen_login_requests_result", "token": "$token", "success": true, "user": "$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 { } else {
webClient.server.loginTokens.invalidate(token) webClient.server.loginTokens.invalidate(token)
webClient.ws.send("""{"action": "listen_login_requests_result", "token": "$token", "success": false}""") 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" -> { "unlisten_login_requests" -> {