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"
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")

View File

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

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.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<String>) {
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()

View File

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

View File

@ -11,12 +11,12 @@ import java.util.concurrent.TimeUnit
object FrontEndInit : ChannelInitializer<Channel>() {
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))
}
}
}

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.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() })
}
}

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.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,

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 (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 {

View File

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

View File

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

View File

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