backend injection, fixed 'remaining bytes!!!', some cleanup, fix listening in browser

This commit is contained in:
creeper123123321 2021-01-23 18:59:22 -03:00
parent b69bf7cb1f
commit ffb8980fb2
7 changed files with 134 additions and 177 deletions

View File

@ -10,6 +10,7 @@ import io.netty.handler.codec.MessageToMessageCodec
import io.netty.handler.flow.FlowControlHandler import io.netty.handler.flow.FlowControlHandler
import io.netty.handler.timeout.ReadTimeoutHandler import io.netty.handler.timeout.ReadTimeoutHandler
import us.myles.ViaVersion.api.data.UserConnection import us.myles.ViaVersion.api.data.UserConnection
import us.myles.ViaVersion.api.protocol.ProtocolPipeline
import us.myles.ViaVersion.api.type.Type import us.myles.ViaVersion.api.type.Type
import us.myles.ViaVersion.exception.CancelDecoderException import us.myles.ViaVersion.exception.CancelDecoderException
import us.myles.ViaVersion.exception.CancelEncoderException import us.myles.ViaVersion.exception.CancelEncoderException
@ -21,15 +22,27 @@ import javax.crypto.Cipher
object ChannelInit : ChannelInitializer<Channel>() { object ChannelInit : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) { override fun initChannel(ch: Channel) {
val user = UserConnection(ch)
CloudPipeline(user)
ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS)) ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
// "crypto" // "crypto"
.addLast("frame", FrameCodec()) .addLast("frame", FrameCodec())
// "compress" / dummy "decompress" // "compress" / dummy "decompress"
.addLast("flow-handler", FlowControlHandler()) .addLast("flow-handler", FlowControlHandler())
.addLast("handler", CloudMinecraftHandler(ConnectionData(
frontChannel = ch,
), other = null, frontEnd = true))
}
}
class BackendInit(val connectionData: ConnectionData) : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) {
val user = UserConnection(ch, true)
ProtocolPipeline(user)
ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
// "crypto"
.addLast("frame", FrameCodec())
// compress
.addLast("via-codec", CloudViaCodec(user)) .addLast("via-codec", CloudViaCodec(user))
.addLast("handler", CloudMinecraftHandler(user, null, frontEnd = true)) .addLast("handler", CloudMinecraftHandler(connectionData, connectionData.frontChannel, frontEnd = false))
} }
} }
@ -49,16 +62,6 @@ class CloudCrypto(val cipherDecode: Cipher, var cipherEncode: Cipher) : MessageT
} }
} }
class BackendInit(val user: UserConnection) : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) {
ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
// "crypto"
.addLast("frame", FrameCodec())
// compress
.addLast("handler", CloudMinecraftHandler(user, null, frontEnd = false))
}
}
class CloudCompressionCodec(val threshold: Int) : MessageToMessageCodec<ByteBuf, ByteBuf>() { class CloudCompressionCodec(val threshold: Int) : MessageToMessageCodec<ByteBuf, ByteBuf>() {
// https://github.com/Gerrygames/ClientViaVersion/blob/master/src/main/java/de/gerrygames/the5zig/clientviaversion/netty/CompressionEncoder.java // https://github.com/Gerrygames/ClientViaVersion/blob/master/src/main/java/de/gerrygames/the5zig/clientviaversion/netty/CompressionEncoder.java
private val inflater: Inflater = private val inflater: Inflater =

View File

@ -3,7 +3,6 @@ package com.github.creeper123123321.viaaas
import com.google.common.net.UrlEscapers import com.google.common.net.UrlEscapers
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.JsonObject import com.google.gson.JsonObject
import de.gerrygames.viarewind.netty.EmptyChannelHandler
import io.ktor.client.request.* import io.ktor.client.request.*
import io.netty.bootstrap.Bootstrap import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf import io.netty.buffer.ByteBuf
@ -17,8 +16,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import us.myles.ViaVersion.api.data.StoredObject
import us.myles.ViaVersion.api.data.UserConnection
import us.myles.ViaVersion.api.protocol.ProtocolVersion import us.myles.ViaVersion.api.protocol.ProtocolVersion
import us.myles.ViaVersion.api.type.Type import us.myles.ViaVersion.api.type.Type
import us.myles.ViaVersion.exception.CancelCodecException import us.myles.ViaVersion.exception.CancelCodecException
@ -39,29 +36,34 @@ import javax.naming.directory.InitialDirContext
val chLogger = LoggerFactory.getLogger("VIAaaS MC Handler") val chLogger = LoggerFactory.getLogger("VIAaaS MC Handler")
class HandlerData( class ConnectionData(
userConnection: UserConnection, val frontChannel: Channel,
var state: MinecraftConnectionState, var backChannel: Channel? = null,
var protocolId: Int? = null, var state: MinecraftConnectionState = HandshakeState(),
var frontOnline: Boolean? = null, // todo
var frontName: String? = null, var frontName: String? = null,
var backName: String? = null, var backName: String? = null,
var backServerId: String? = null,
var backPublicKey: PublicKey? = null, var backPublicKey: PublicKey? = null,
var backToken: ByteArray? = null, var backToken: ByteArray? = null,
var frontToken: ByteArray? = null, var frontToken: ByteArray? = null,
var frontId: String? = null var frontServerId: String? = null,
) : StoredObject(userConnection) var backServerId: String? = null,
var frontVer: Int? = null,
var backVer: Int? = null,
) {
val frontHandler get() = frontChannel.pipeline().get(CloudMinecraftHandler::class.java)
val backHandler get() = backChannel?.pipeline()?.get(CloudMinecraftHandler::class.java)
}
class CloudMinecraftHandler( class CloudMinecraftHandler(
val user: UserConnection, val data: ConnectionData,
var other: Channel?, var other: Channel?,
val frontEnd: Boolean val frontEnd: Boolean
) : SimpleChannelInboundHandler<ByteBuf>() { ) : SimpleChannelInboundHandler<ByteBuf>() {
val data get() = user.get(HandlerData::class.java)!! var remoteAddress: SocketAddress? = null
var address: SocketAddress? = null
override fun channelRead0(ctx: ChannelHandlerContext, msg: ByteBuf) { override fun channelRead0(ctx: ChannelHandlerContext, msg: ByteBuf) {
if (ctx.channel().isActive && !user.isPendingDisconnect && msg.isReadable) { if (ctx.channel().isActive && msg.isReadable) {
data.state.handleMessage(this, ctx, msg) data.state.handleMessage(this, ctx, msg)
if (msg.isReadable) throw IllegalStateException("Remaining bytes!!!") if (msg.isReadable) throw IllegalStateException("Remaining bytes!!!")
//other?.write(msg.retain()) //other?.write(msg.retain())
@ -69,10 +71,7 @@ class CloudMinecraftHandler(
} }
override fun channelActive(ctx: ChannelHandlerContext) { override fun channelActive(ctx: ChannelHandlerContext) {
address = ctx.channel().remoteAddress() remoteAddress = ctx.channel().remoteAddress()
if (user.get(HandlerData::class.java) == null) {
user.put(HandlerData(user, HandshakeState()))
}
} }
override fun channelInactive(ctx: ChannelHandlerContext) { override fun channelInactive(ctx: ChannelHandlerContext) {
@ -106,12 +105,11 @@ interface MinecraftConnectionState {
) )
fun disconnect(handler: CloudMinecraftHandler, msg: String) { fun disconnect(handler: CloudMinecraftHandler, msg: String) {
chLogger.info("Disconnected ${handler.address}: $msg") chLogger.info("Disconnected ${handler.remoteAddress}: $msg")
handler.user.isPendingDisconnect = true
} }
fun onInactivated(handler: CloudMinecraftHandler) { fun onInactivated(handler: CloudMinecraftHandler) {
chLogger.info(handler.address?.toString() + " inactivated") chLogger.info(handler.remoteAddress?.toString() + " inactivated")
} }
} }
@ -119,76 +117,80 @@ class HandshakeState : MinecraftConnectionState {
override fun handleMessage(handler: CloudMinecraftHandler, ctx: ChannelHandlerContext, msg: ByteBuf) { override fun handleMessage(handler: CloudMinecraftHandler, ctx: ChannelHandlerContext, msg: ByteBuf) {
val packet = PacketRegistry.decode( val packet = PacketRegistry.decode(
msg, msg,
ProtocolVersion.getProtocol(handler.user.protocolInfo!!.serverProtocolVersion), ProtocolVersion.v1_8, // we still dont know what protocol it is
State.HANDSHAKE, State.HANDSHAKE,
handler.frontEnd handler.frontEnd
) )
if (packet !is HandshakePacket) throw IllegalArgumentException("Invalid packet!") if (packet !is HandshakePacket) throw IllegalArgumentException("Invalid packet!")
handler.data.protocolId = packet.protocolId
handler.data.frontVer = packet.protocolId
when (packet.nextState.ordinal) { when (packet.nextState.ordinal) {
1 -> handler.data.state = StatusState 1 -> handler.data.state = StatusState
2 -> handler.data.state = LoginState 2 -> handler.data.state = LoginState
else -> throw IllegalStateException("Invalid next state") else -> throw IllegalStateException("Invalid next state")
} }
if (!handler.user.get(CloudData::class.java)!!.hadHostname && VIAaaSConfig.requireHostName) { val parsed = VIAaaSAddress().parse(packet.address.substringBefore(0.toChar()), VIAaaSConfig.hostName)
val backProto = parsed.protocol ?: 47 // todo autodetection
val hadHostname = parsed.viaSuffix != null
packet.address = parsed.realAddress!!
packet.port = parsed.port ?: if (VIAaaSConfig.defaultBackendPort == -1) {
packet.port
} else {
VIAaaSConfig.defaultBackendPort
}
handler.data.backVer = backProto
handler.data.frontOnline = parsed.online
handler.data.backName = parsed.altUsername
val playerAddr = handler.data.frontHandler.remoteAddress
chLogger.info("Connecting $playerAddr (${handler.data.frontVer}) -> ${packet.address}:${packet.port} ($backProto)")
if (!hadHostname && VIAaaSConfig.requireHostName) {
throw UnsupportedOperationException("This VIAaaS instance requires you to use the hostname") throw UnsupportedOperationException("This VIAaaS instance requires you to use the hostname")
} }
handler.user.channel!!.setAutoRead(false) handler.data.frontChannel.setAutoRead(false)
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
val frontHandler = handler.user.channel!!.pipeline().get(CloudMinecraftHandler::class.java) val frontHandler = handler.data.frontHandler
try { try {
var srvResolvedAddr = packet.address val srvResolved = resolveSrv(packet.address, packet.port)
var srvResolvedPort = packet.port packet.address = srvResolved.first
if (srvResolvedPort == 25565) { packet.port = srvResolved.second
try {
// https://github.com/GeyserMC/Geyser/blob/99e72f35b308542cf0dbfb5b58816503c3d6a129/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
val attr = InitialDirContext()
.getAttributes("dns:///_minecraft._tcp.$srvResolvedAddr", arrayOf("SRV"))["SRV"]
if (attr != null && attr.size() > 0) {
val record = (attr.get(0) as String).split(" ")
srvResolvedAddr = record[3]
srvResolvedPort = record[2].toInt()
}
} catch (ignored: NameNotFoundException) {
}
}
val socketAddr = InetSocketAddress(InetAddress.getByName(srvResolvedAddr), srvResolvedPort)
val addrInfo = socketAddr.address
if (VIAaaSConfig.blockLocalAddress && (addrInfo.isSiteLocalAddress
|| addrInfo.isLoopbackAddress
|| addrInfo.isLinkLocalAddress
|| addrInfo.isAnyLocalAddress)
) throw SecurityException("Local addresses aren't allowed")
val bootstrap = Bootstrap().handler(BackendInit(handler.user)) val socketAddr = InetSocketAddress(InetAddress.getByName(packet.address), packet.port)
if (checkLocalAddress(socketAddr.address)) {
throw SecurityException("Local addresses aren't allowed")
}
val bootstrap = Bootstrap().handler(BackendInit(handler.data))
.channelFactory(channelSocketFactory()) .channelFactory(channelSocketFactory())
.group(handler.user.channel!!.eventLoop()) .group(handler.data.frontChannel.eventLoop())
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15_000) // Half of mc timeout .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15_000) // Half of mc timeout
.connect(socketAddr) .connect(socketAddr)
bootstrap.addListener { bootstrap.addListener {
if (it.isSuccess) { if (it.isSuccess) {
CloudHeadProtocol.logger.info("Connected ${frontHandler.address} -> $socketAddr") chLogger.info("Connected ${frontHandler.remoteAddress} -> $socketAddr")
val backChan = bootstrap.channel() as SocketChannel val backChan = bootstrap.channel() as SocketChannel
backChan.pipeline().get(CloudMinecraftHandler::class.java).other = handler.user.channel handler.data.backChannel = backChan
frontHandler.other = backChan frontHandler.other = backChan
packet.address = srvResolvedAddr
packet.port = srvResolvedPort
forward(handler, packet) forward(handler, packet)
backChan.flush() backChan.flush()
handler.user.channel!!.setAutoRead(true) handler.data.frontChannel.setAutoRead(true)
} else { } else {
// We're in the event loop // We're in the event loop
frontHandler.disconnect("Couldn't connect: " + it.cause().toString()) frontHandler.disconnect("Couldn't connect: " + it.cause().toString())
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
handler.user.channel!!.eventLoop().submit { handler.data.frontChannel.eventLoop().submit {
frontHandler.disconnect("Couldn't connect: $e") frontHandler.disconnect("Couldn't connect: $e")
} }
} }
@ -196,7 +198,7 @@ class HandshakeState : MinecraftConnectionState {
} }
override fun disconnect(handler: CloudMinecraftHandler, msg: String) { override fun disconnect(handler: CloudMinecraftHandler, msg: String) {
handler.user.channel?.close() // Not worth logging handler.data.frontChannel.close() // Not worth logging
} }
override fun onInactivated(handler: CloudMinecraftHandler) { override fun onInactivated(handler: CloudMinecraftHandler) {
@ -208,7 +210,7 @@ object LoginState : MinecraftConnectionState {
override fun handleMessage(handler: CloudMinecraftHandler, ctx: ChannelHandlerContext, msg: ByteBuf) { override fun handleMessage(handler: CloudMinecraftHandler, ctx: ChannelHandlerContext, msg: ByteBuf) {
val packet = PacketRegistry.decode( val packet = PacketRegistry.decode(
msg, msg,
ProtocolVersion.getProtocol(handler.user.protocolInfo!!.serverProtocolVersion), ProtocolVersion.getProtocol(handler.data.frontVer!!),
State.LOGIN, State.LOGIN,
handler.frontEnd handler.frontEnd
) )
@ -232,16 +234,24 @@ object LoginState : MinecraftConnectionState {
} }
private fun handleCompression(handler: CloudMinecraftHandler, setCompression: SetCompression) { private fun handleCompression(handler: CloudMinecraftHandler, setCompression: SetCompression) {
val pipe = handler.user.channel!!.pipeline() val pipe = handler.data.frontChannel.pipeline()
val threshold = setCompression.threshold val threshold = setCompression.threshold
val backPipe = pipe.get(CloudMinecraftHandler::class.java).other!!.pipeline() val backPipe = pipe.get(CloudMinecraftHandler::class.java).other!!.pipeline()
if (threshold != -1) {
backPipe.addAfter("frame", "compress", CloudCompressionCodec(threshold)) backPipe.addAfter("frame", "compress", CloudCompressionCodec(threshold))
} else if (backPipe.get("compress") != null) {
backPipe.remove("compress")
}
forward(handler, setCompression) forward(handler, setCompression)
if (threshold != -1) {
pipe.addAfter("frame", "compress", CloudCompressionCodec(threshold)) pipe.addAfter("frame", "compress", CloudCompressionCodec(threshold))
pipe.addAfter("frame", "decompress", EmptyChannelHandler()) // ViaRewind compat workaround // todo viarewind backend compression
} else if (pipe.get("compress") != null) {
pipe.remove("compress")
}
} }
fun handleCryptoRequest(handler: CloudMinecraftHandler, cryptoRequest: CryptoRequest) { fun handleCryptoRequest(handler: CloudMinecraftHandler, cryptoRequest: CryptoRequest) {
@ -261,7 +271,7 @@ object LoginState : MinecraftConnectionState {
it it
} }
data.frontToken = token data.frontToken = token
data.frontId = id data.frontServerId = id
cryptoRequest.serverId = id cryptoRequest.serverId = id
cryptoRequest.publicKey = mcCryptoKey.public cryptoRequest.publicKey = mcCryptoKey.public
@ -281,9 +291,9 @@ object LoginState : MinecraftConnectionState {
val aesEn = mcCfb8(frontKey, Cipher.ENCRYPT_MODE) val aesEn = mcCfb8(frontKey, Cipher.ENCRYPT_MODE)
val aesDe = mcCfb8(frontKey, Cipher.DECRYPT_MODE) val aesDe = mcCfb8(frontKey, Cipher.DECRYPT_MODE)
handler.user.channel!!.pipeline().addBefore("frame", "crypto", CloudCrypto(aesDe, aesEn)) handler.data.frontChannel.pipeline().addBefore("frame", "crypto", CloudCrypto(aesDe, aesEn))
generateServerHash(handler.data.frontId!!, frontKey, mcCryptoKey.public) generateServerHash(handler.data.frontServerId!!, frontKey, mcCryptoKey.public)
} }
val backKey = ByteArray(16).let { val backKey = ByteArray(16).let {
@ -293,14 +303,13 @@ object LoginState : MinecraftConnectionState {
val backHash = generateServerHash(handler.data.backServerId!!, backKey, handler.data.backPublicKey!!) val backHash = generateServerHash(handler.data.backServerId!!, backKey, handler.data.backPublicKey!!)
handler.user.channel!!.setAutoRead(false) handler.data.frontChannel.setAutoRead(false)
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
try { try {
val profile = httpClient.get<JsonObject?>( val profile = httpClient.get<JsonObject?>(
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" +
"${ UrlEscapers.urlFormParameterEscaper().escape(handler.data.frontName!!) +
UrlEscapers.urlFormParameterEscaper().escape(handler.data.frontName!!) "&serverId=$frontHash"
}&serverId=$frontHash"
) )
?: throw IllegalArgumentException("Couldn't authenticate with session servers") ?: throw IllegalArgumentException("Couldn't authenticate with session servers")
@ -308,7 +317,7 @@ object LoginState : MinecraftConnectionState {
fromUndashed(profile.get("id")!!.asString), fromUndashed(profile.get("id")!!.asString),
handler.data.backName!!, handler.data.backName!!,
backHash, backHash,
handler.address!!, // Frontend handler handler.remoteAddress!!, // Frontend handler
handler.data.backPublicKey!! handler.data.backPublicKey!!
) )
@ -331,13 +340,13 @@ object LoginState : MinecraftConnectionState {
} catch (e: Exception) { } catch (e: Exception) {
handler.disconnect("Online mode error: $e") handler.disconnect("Online mode error: $e")
} }
handler.user.channel!!.setAutoRead(true) handler.data.frontChannel.setAutoRead(true)
} }
} }
fun handleLoginStart(handler: CloudMinecraftHandler, loginStart: LoginStart) { fun handleLoginStart(handler: CloudMinecraftHandler, loginStart: LoginStart) {
handler.data.frontName = loginStart.username handler.data.frontName = loginStart.username
handler.data.backName = handler.user.get(CloudData::class.java)!!.altName ?: handler.data.frontName handler.data.backName = handler.data.backName ?: handler.data.frontName
loginStart.username = handler.data.backName!! loginStart.username = handler.data.backName!!
forward(handler, loginStart) forward(handler, loginStart)
@ -350,9 +359,9 @@ object LoginState : MinecraftConnectionState {
try { try {
packet.writeByte(0) // id 0 disconnect packet.writeByte(0) // id 0 disconnect
Type.STRING.write(packet, Gson().toJson("[VIAaaS] §c$msg")) Type.STRING.write(packet, Gson().toJson("[VIAaaS] §c$msg"))
handler.user handler.data.frontChannel
.sendRawPacketFuture(packet.retain()) .writeAndFlush(packet.retain())
.addListener { handler.user.channel?.close() } .addListener { handler.data.frontChannel.close() }
} finally { } finally {
packet.release() packet.release()
} }
@ -364,7 +373,8 @@ object StatusState : MinecraftConnectionState {
val i = msg.readerIndex() val i = msg.readerIndex()
if (Type.VAR_INT.readPrimitive(msg) !in 0..1) throw IllegalArgumentException("Invalid packet id!") if (Type.VAR_INT.readPrimitive(msg) !in 0..1) throw IllegalArgumentException("Invalid packet id!")
msg.readerIndex(i) msg.readerIndex(i)
handler.other!!.write(msg.retain()) handler.other!!.write(msg.retainedSlice())
msg.clear()
} }
override fun disconnect(handler: CloudMinecraftHandler, msg: String) { override fun disconnect(handler: CloudMinecraftHandler, msg: String) {
@ -377,8 +387,8 @@ object StatusState : MinecraftConnectionState {
packet, """{"version": {"name": "VIAaaS", "protocol": -1}, "players": packet, """{"version": {"name": "VIAaaS", "protocol": -1}, "players":
| {"max": 0, "online": 0, "sample": []}, "description": {"text": ${Gson().toJson("§c$msg")}}}""".trimMargin() | {"max": 0, "online": 0, "sample": []}, "description": {"text": ${Gson().toJson("§c$msg")}}}""".trimMargin()
) )
handler.user.sendRawPacketFuture(packet.retain()) handler.data.frontChannel.writeAndFlush(packet.retain())
.addListener { handler.user.channel?.close() } .addListener { handler.data.frontChannel.close() }
} finally { } finally {
packet.release() packet.release()
} }
@ -390,12 +400,13 @@ object PlayState : MinecraftConnectionState {
val i = msg.readerIndex() val i = msg.readerIndex()
if (Type.VAR_INT.readPrimitive(msg) !in 0..127) throw IllegalArgumentException("Invalid packet id!") if (Type.VAR_INT.readPrimitive(msg) !in 0..127) throw IllegalArgumentException("Invalid packet id!")
msg.readerIndex(i) msg.readerIndex(i)
handler.other!!.write(msg.retain()) handler.other!!.write(msg.retainedSlice())
msg.clear()
} }
override fun disconnect(handler: CloudMinecraftHandler, msg: String) { override fun disconnect(handler: CloudMinecraftHandler, msg: String) {
super.disconnect(handler, msg) super.disconnect(handler, msg)
handler.user.channel?.close() handler.data.frontChannel.close()
} }
} }
@ -440,9 +451,32 @@ fun generateServerHash(serverId: String, sharedSecret: ByteArray?, key: PublicKe
private fun forward(handler: CloudMinecraftHandler, packet: Packet) { private fun forward(handler: CloudMinecraftHandler, packet: Packet) {
val msg = ByteBufAllocator.DEFAULT.buffer() val msg = ByteBufAllocator.DEFAULT.buffer()
try { try {
PacketRegistry.encode(packet, msg, ProtocolVersion.getProtocol(handler.data.protocolId!!)) PacketRegistry.encode(packet, msg, ProtocolVersion.getProtocol(handler.data.frontVer!!))
handler.other!!.write(msg.retain()) handler.other!!.write(msg.retain())
} finally { } finally {
msg.release() msg.release()
} }
} }
private fun resolveSrv(address: String, port: Int): Pair<String, Int> {
if (port == 25565) {
try {
// https://github.com/GeyserMC/Geyser/blob/99e72f35b308542cf0dbfb5b58816503c3d6a129/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
val attr = InitialDirContext()
.getAttributes("dns:///_minecraft._tcp.$address", arrayOf("SRV"))["SRV"]
if (attr != null && attr.size() > 0) {
val record = (attr.get(0) as String).split(" ")
return record[3] to record[2].toInt()
}
} catch (ignored: NameNotFoundException) {
}
}
return address to port
}
private fun checkLocalAddress(inetAddress: InetAddress): Boolean {
return VIAaaSConfig.blockLocalAddress && (inetAddress.isSiteLocalAddress
|| inetAddress.isLoopbackAddress
|| inetAddress.isLinkLocalAddress
|| inetAddress.isAnyLocalAddress)
}

View File

@ -185,8 +185,7 @@ class CloudTask(val obj: Future<*>) : TaskId {
object CloudVersionProvider : VersionProvider() { object CloudVersionProvider : VersionProvider() {
override fun getServerProtocol(connection: UserConnection): Int { override fun getServerProtocol(connection: UserConnection): Int {
val data = connection.get(CloudData::class.java) val ver = connection.channel!!.pipeline().get(CloudMinecraftHandler::class.java).data.backVer
val ver = data?.backendVer
if (ver != null) return ver if (ver != null) return ver
return super.getServerProtocol(connection) return super.getServerProtocol(connection)
} }

View File

@ -1,76 +0,0 @@
package com.github.creeper123123321.viaaas
import org.slf4j.LoggerFactory
import us.myles.ViaVersion.api.PacketWrapper
import us.myles.ViaVersion.api.data.StoredObject
import us.myles.ViaVersion.api.data.UserConnection
import us.myles.ViaVersion.api.protocol.Protocol
import us.myles.ViaVersion.api.protocol.ProtocolPipeline
import us.myles.ViaVersion.api.protocol.SimpleProtocol
import us.myles.ViaVersion.api.remapper.PacketRemapper
import us.myles.ViaVersion.api.type.Type
import us.myles.ViaVersion.packets.State
class CloudPipeline(userConnection: UserConnection) : ProtocolPipeline(userConnection) {
override fun registerPackets() {
super.registerPackets()
add(CloudHeadProtocol) // add() will add tail protocol
}
override fun add(protocol: Protocol<*, *, *, *>?) {
super.add(protocol)
pipes().removeIf { it == CloudHeadProtocol }
pipes().add(0, CloudHeadProtocol)
}
}
object CloudHeadProtocol : SimpleProtocol() {
val logger = LoggerFactory.getLogger("CloudHandlerProtocol")
override fun registerPackets() {
this.registerIncoming(State.HANDSHAKE, 0, 0, object : PacketRemapper() {
override fun registerMap() {
handler { wrapper: PacketWrapper ->
val playerVer = wrapper.passthrough(Type.VAR_INT)
val addr = wrapper.read(Type.STRING) // Server Address
val receivedPort = wrapper.read(Type.UNSIGNED_SHORT)
val parsed = VIAaaSAddress().parse(addr.substringBefore(0.toChar()), VIAaaSConfig.hostName)
val backPort = parsed.port ?: if (VIAaaSConfig.defaultBackendPort == -1) {
receivedPort
} else {
VIAaaSConfig.defaultBackendPort
}
val backAddr = parsed.realAddress
val backProto = parsed.protocol ?: 47
wrapper.write(Type.STRING, backAddr)
wrapper.write(Type.UNSIGNED_SHORT, backPort)
val playerAddr = wrapper.user().channel!!.pipeline()
.get(CloudMinecraftHandler::class.java)!!.address
logger.info("Connecting $playerAddr ($playerVer) -> $backAddr:$backPort ($backProto)")
wrapper.user().put(
CloudData(
userConnection = wrapper.user(),
backendVer = backProto,
frontOnline = parsed.online,
altName = parsed.altUsername,
hadHostname = parsed.viaSuffix != null
)
)
wrapper.passthrough(Type.VAR_INT) // Next state
}
}
})
}
}
data class CloudData(
val userConnection: UserConnection,
var backendVer: Int,
var frontOnline: Boolean,
var altName: String?,
var hadHostname: Boolean
) : StoredObject(userConnection)

View File

@ -105,7 +105,7 @@ fun main(args: Array<String>) {
MappingDataLoader.enableMappingsCache() MappingDataLoader.enableMappingsCache()
Via.getManager().init() Via.getManager().init()
CloudRewind.init(ViaRewindConfigImpl(File("config/viarewind.yml"))) CloudRewind.init(ViaRewindConfigImpl(File("config/viarewind.yml")))
CloudBackwards.init(File("config/viabackwards.yml")) CloudBackwards.init(File("config/viabackwards"))
val parent = eventLoopGroup() val parent = eventLoopGroup()
val child = eventLoopGroup() val child = eventLoopGroup()

View File

@ -38,9 +38,6 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
import kotlin.collections.set import kotlin.collections.set
// todo https://minecraft.id/documentation
val viaWebServer = WebDashboardServer() val viaWebServer = WebDashboardServer()
val webLogger = LoggerFactory.getLogger("VIAaaS Web") val webLogger = LoggerFactory.getLogger("VIAaaS Web")

View File

@ -221,11 +221,11 @@ function renderActions() {
add.innerText = "Listen to " + username; add.innerText = "Listen to " + username;
add.href = "#"; add.href = "#";
add.onclick = () => { add.onclick = () => {
mcauth_code = null;
socket.send(JSON.stringify({ socket.send(JSON.stringify({
"action": "minecraft_id_login", "action": "minecraft_id_login",
"username": username, "username": username,
"code": mcauth_code})); "code": mcauth_code}));
mcauth_code = null;
}; };
actions.appendChild(p); actions.appendChild(p);
} }