mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2024-11-15 10:55:27 +01:00
protocol autodetection, viaaas info in server brand and ping
This commit is contained in:
parent
d3325612a8
commit
33b40e6eea
@ -8,7 +8,7 @@ How to use: server.example.com._p25565._v1_12_2._ofalse._uBACKUSERNAME.viaaas.ex
|
||||
Parts:
|
||||
- ```server.example.com```: backend server address
|
||||
- ```_p```: backend port
|
||||
- ```_v```: backend version (protocol id https://wiki.vg/Protocol_version_numbers or name with underline instead of dots). Current default is 1.8, may change to auto detection in the future
|
||||
- ```_v```: backend version (protocol id https://wiki.vg/Protocol_version_numbers or name with underline instead of dots). ```AUTO``` is default and 1.8 is fallback if it fails.
|
||||
- ```_o```: ```t``` to force online mode in frontend, ```f``` to disable online mode in frontend. If not set, it will be based on backend online mode.
|
||||
- ```_u```: username to use in backend connection
|
||||
- ```viaaas.example.com```: hostname suffix (defined in config)
|
||||
@ -36,7 +36,7 @@ How to start VIAaaS server:
|
||||
- ```java -jar VIAaaS-all.jar```
|
||||
|
||||
Usage for offline mode:
|
||||
- Connect to ```mc.example.com._v1_8.viaaas.localhost```
|
||||
- Connect to ```mc.example.com.viaaas.localhost```
|
||||
|
||||
Usage for online mode:
|
||||
- You can use two accounts (avoids Bad Login error), the same account for front-end and back-end connections or use ```_of```
|
||||
@ -48,7 +48,7 @@ Usage for online mode:
|
||||
- Go to VIAaaS auth webpage (https://localhost:25543/), configure the CORS Proxy URL (something like http://localhost:8080/,
|
||||
note the ending slash) and listen to the username A that you're using to connect to the proxy.
|
||||
- Add the account B you'll use in ```_u(account B)``` parameter to browser auth page.
|
||||
- Connect to ```mc.example.com._v1_8._u(account B).viaaas.localhost``` (```_u``` parameter can be removed if you are using the same username)
|
||||
- Connect to ```mc.example.com._u(account B).viaaas.localhost``` (```_u``` parameter can be removed if you are using the same username)
|
||||
- Approve the login in auth webpage
|
||||
- If you use the same online mode account, your client will give Bad Login after you approve it in your browser. You can use
|
||||
https://www.curseforge.com/minecraft/mc-mods/auth-me for reauthenticating the client.
|
||||
|
@ -3,6 +3,7 @@ package com.github.creeper123123321.viaaas
|
||||
import com.github.creeper123123321.viaaas.config.VIAaaSConfig
|
||||
import com.google.common.base.Preconditions
|
||||
import com.google.common.primitives.Ints
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.handler.codec.DecoderException
|
||||
import org.slf4j.LoggerFactory
|
||||
@ -132,4 +133,6 @@ fun writeFlushClose(ch: Channel, obj: Any) {
|
||||
ch.writeAndFlush(obj).addListener { ch.close() }
|
||||
}
|
||||
|
||||
val secureRandom = if (VIAaaSConfig.useStrongRandom) SecureRandom.getInstanceStrong() else SecureRandom()
|
||||
val secureRandom = if (VIAaaSConfig.useStrongRandom) SecureRandom.getInstanceStrong() else SecureRandom()
|
||||
|
||||
fun readableToByteArray(byteBuf: ByteBuf) = ByteArray(byteBuf.readableBytes()).also { byteBuf.readBytes(it) }
|
@ -7,6 +7,7 @@ import com.github.creeper123123321.viaaas.handler.FrontEndInit
|
||||
import com.github.creeper123123321.viaaas.platform.*
|
||||
import com.github.creeper123123321.viaaas.web.ViaWebApp
|
||||
import com.github.creeper123123321.viaaas.web.WebDashboardServer
|
||||
import com.google.gson.JsonParser
|
||||
import de.gerrygames.viarewind.api.ViaRewindConfigImpl
|
||||
import io.ktor.application.*
|
||||
import io.ktor.client.*
|
||||
@ -36,17 +37,15 @@ import io.netty.util.concurrent.Future
|
||||
import us.myles.ViaVersion.ViaManager
|
||||
import us.myles.ViaVersion.api.Via
|
||||
import us.myles.ViaVersion.api.data.MappingDataLoader
|
||||
import us.myles.ViaVersion.util.GsonUtil
|
||||
import us.myles.viaversion.libs.gson.JsonObject
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
import java.io.File
|
||||
import java.net.InetAddress
|
||||
import java.security.KeyPairGenerator
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
val viaaasVer = GsonUtil.getGson().fromJson(
|
||||
AspirinPlatform::class.java.classLoader.getResourceAsStream("viaaas_info.json")!!.reader(Charsets.UTF_8).readText(),
|
||||
JsonObject::class.java
|
||||
).get("version").asString
|
||||
val viaaasVer = JsonParser.parseString(
|
||||
AspirinPlatform::class.java.classLoader.getResourceAsStream("viaaas_info.json")!!.reader(Charsets.UTF_8).readText()
|
||||
).asJsonObject.get("version").asString
|
||||
val viaWebServer = WebDashboardServer()
|
||||
var runningServer = true
|
||||
val httpClient = HttpClient {
|
||||
@ -89,6 +88,9 @@ fun channelSocketFactory(): ChannelFactory<SocketChannel> {
|
||||
return ChannelFactory { NioSocketChannel() }
|
||||
}
|
||||
|
||||
val parentLoop = eventLoopGroup()
|
||||
val childLoop = eventLoopGroup()
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
// Stolen from https://github.com/VelocityPowered/Velocity/blob/dev/1.1.0/proxy/src/main/java/com/velocitypowered/proxy/Velocity.java
|
||||
if (System.getProperty("io.netty.allocator.maxOrder") == null) {
|
||||
@ -109,14 +111,12 @@ fun main(args: Array<String>) {
|
||||
)
|
||||
MappingDataLoader.enableMappingsCache()
|
||||
Via.getManager().init()
|
||||
ProtocolVersion.register(-2, "AUTO")
|
||||
AspirinRewind.init(ViaRewindConfigImpl(File("config/viarewind.yml")))
|
||||
AspirinBackwards.init(File("config/viabackwards"))
|
||||
|
||||
val parent = eventLoopGroup()
|
||||
val child = eventLoopGroup()
|
||||
|
||||
val future = ServerBootstrap()
|
||||
.group(parent, child)
|
||||
.group(parentLoop, childLoop)
|
||||
.channelFactory(channelServerSocketFactory())
|
||||
.childHandler(FrontEndInit)
|
||||
.childOption(ChannelOption.IP_TOS, 0x18)
|
||||
@ -138,7 +138,7 @@ fun main(args: Array<String>) {
|
||||
|
||||
ktorServer?.stop(1000, 1000)
|
||||
httpClient.close()
|
||||
listOf<Future<*>>(future.channel().close(), parent.shutdownGracefully(), child.shutdownGracefully())
|
||||
listOf<Future<*>>(future.channel().close(), parentLoop.shutdownGracefully(), childLoop.shutdownGracefully())
|
||||
.forEach { it.sync() }
|
||||
|
||||
Via.getManager().destroy()
|
||||
|
@ -32,7 +32,6 @@ class VIAaaSAddress {
|
||||
}.asReversed().joinToString(".")
|
||||
|
||||
viaOptions = optionsList.asReversed().joinToString(".")
|
||||
|
||||
viaSuffix = viaHostName
|
||||
|
||||
return this
|
||||
@ -58,6 +57,9 @@ class VIAaaSAddress {
|
||||
protocol = it.version
|
||||
}
|
||||
}
|
||||
if (protocol == -2) {
|
||||
protocol = null
|
||||
}
|
||||
}
|
||||
part.startsWith("_u", ignoreCase = true) -> {
|
||||
if (arg.length > 16) throw IllegalArgumentException("Invalid username")
|
||||
|
@ -14,7 +14,7 @@ class MinecraftCodec : MessageToMessageCodec<ByteBuf, Packet>() {
|
||||
val buf = ByteBufAllocator.DEFAULT.buffer()
|
||||
try {
|
||||
val handler = ctx.pipeline().get(MinecraftHandler::class.java)
|
||||
PacketRegistry.encode(msg, buf, handler.data.frontVer!!)
|
||||
PacketRegistry.encode(msg, buf, handler.data.frontVer!!, serverBound = !handler.frontEnd)
|
||||
out.add(buf.retain())
|
||||
} finally {
|
||||
buf.release()
|
||||
|
@ -35,4 +35,6 @@ object VIAaaSConfig : Config(File("config/viaaas.yml")) {
|
||||
emptyList<String>()
|
||||
)!!.map { it as String }
|
||||
val forceOnlineMode: Boolean get() = this.getBoolean("force-online-mode", false)
|
||||
val showVersionPing: Boolean get() = this.getBoolean("show-version-ping", true)
|
||||
val showBrandInfo: Boolean get() = this.getBoolean("show-brand-info", true)
|
||||
}
|
@ -2,6 +2,7 @@ package com.github.creeper123123321.viaaas.handler
|
||||
|
||||
import com.github.creeper123123321.viaaas.codec.FrameCodec
|
||||
import com.github.creeper123123321.viaaas.codec.MinecraftCodec
|
||||
import com.github.creeper123123321.viaaas.handler.autoprotocol.ProtocolDetectorHandler
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelInitializer
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler
|
||||
@ -19,6 +20,11 @@ class BackEndInit(val connectionData: ConnectionData) : ChannelInitializer<Chann
|
||||
// compress
|
||||
.addLast("via-codec", ViaCodec(user))
|
||||
.addLast("mc", MinecraftCodec())
|
||||
.also {
|
||||
if (connectionData.backVer == null) {
|
||||
it.addLast("protocol-detector", ProtocolDetectorHandler(connectionData))
|
||||
}
|
||||
}
|
||||
.addLast("handler", MinecraftHandler(connectionData, frontEnd = false))
|
||||
}
|
||||
}
|
@ -17,10 +17,6 @@ object FrontEndInit : ChannelInitializer<Channel>() {
|
||||
// "compress"
|
||||
.addLast("flow-handler", FlowControlHandler())
|
||||
.addLast("mc", MinecraftCodec())
|
||||
.addLast(
|
||||
"handler", MinecraftHandler(
|
||||
ConnectionData(frontChannel = ch), frontEnd = true
|
||||
)
|
||||
)
|
||||
.addLast("handler", MinecraftHandler(ConnectionData(frontChannel = ch), frontEnd = true))
|
||||
}
|
||||
}
|
@ -2,8 +2,10 @@ package com.github.creeper123123321.viaaas.handler
|
||||
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.send
|
||||
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
|
||||
fun forward(handler: MinecraftHandler, packet: Packet, flush: Boolean = false) {
|
||||
send(handler.other!!, packet, flush)
|
||||
}
|
||||
}
|
||||
|
||||
fun is1_7(handler: MinecraftHandler) = handler.data.frontVer!! <= ProtocolVersion.v1_7_6.version
|
@ -0,0 +1,37 @@
|
||||
package com.github.creeper123123321.viaaas.handler.autoprotocol
|
||||
|
||||
import com.github.creeper123123321.viaaas.handler.MinecraftHandler
|
||||
import com.github.creeper123123321.viaaas.handler.state.MinecraftConnectionState
|
||||
import com.github.creeper123123321.viaaas.mcLogger
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusResponse
|
||||
import com.google.gson.JsonParser
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
import us.myles.ViaVersion.packets.State
|
||||
import java.nio.channels.ClosedChannelException
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ProtocolDetectionState(val future: CompletableFuture<ProtocolVersion>) : MinecraftConnectionState {
|
||||
override val state: State
|
||||
get() = State.STATUS
|
||||
|
||||
override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) {
|
||||
handler.data.frontChannel.close()
|
||||
if (packet !is StatusResponse) throw IllegalArgumentException()
|
||||
val ver = ProtocolVersion.getProtocol(
|
||||
JsonParser.parseString(packet.json).asJsonObject.getAsJsonObject("version").get("protocol").asInt
|
||||
)
|
||||
future.complete(ver)
|
||||
mcLogger.info("Auto-detected $ver for ${handler.remoteAddress}")
|
||||
}
|
||||
|
||||
override fun disconnect(handler: MinecraftHandler, msg: String) {
|
||||
super.disconnect(handler, msg)
|
||||
handler.data.frontChannel.close()
|
||||
}
|
||||
|
||||
override fun onInactivated(handler: MinecraftHandler) {
|
||||
future.completeExceptionally(ClosedChannelException())
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.github.creeper123123321.viaaas.handler.autoprotocol
|
||||
|
||||
import com.github.creeper123123321.viaaas.childLoop
|
||||
import com.github.creeper123123321.viaaas.codec.FrameCodec
|
||||
import com.github.creeper123123321.viaaas.codec.MinecraftCodec
|
||||
import com.github.creeper123123321.viaaas.handler.ConnectionData
|
||||
import com.github.creeper123123321.viaaas.handler.MinecraftHandler
|
||||
import com.github.creeper123123321.viaaas.packet.handshake.Handshake
|
||||
import com.github.creeper123123321.viaaas.mcLogger
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusRequest
|
||||
import com.github.creeper123123321.viaaas.send
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.net.InetSocketAddress
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler
|
||||
import io.netty.channel.socket.nio.NioSocketChannel
|
||||
import com.google.common.cache.CacheLoader
|
||||
import java.util.concurrent.TimeUnit
|
||||
import com.google.common.cache.CacheBuilder
|
||||
import io.netty.bootstrap.Bootstrap
|
||||
import io.netty.channel.*
|
||||
import io.netty.util.concurrent.Future
|
||||
import us.myles.ViaVersion.packets.State
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
object ProtocolDetector {
|
||||
private val SERVER_VER = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(100, TimeUnit.SECONDS)
|
||||
.build(CacheLoader.from { address: InetSocketAddress? ->
|
||||
val future = CompletableFuture<ProtocolVersion>()
|
||||
try {
|
||||
val ch: ChannelFuture = Bootstrap()
|
||||
.group(childLoop)
|
||||
.channel(NioSocketChannel::class.java)
|
||||
.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()
|
||||
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
|
||||
.addLast("frame", FrameCodec())
|
||||
.addLast("mc", MinecraftCodec())
|
||||
.addLast("handler", MinecraftHandler(data, frontEnd = false))
|
||||
}
|
||||
})
|
||||
.connect(address!!)
|
||||
ch.addListener { future1: Future<in Void> ->
|
||||
if (!future1.isSuccess) {
|
||||
future.completeExceptionally(future1.cause())
|
||||
} else {
|
||||
ch.channel().eventLoop().execute {
|
||||
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)
|
||||
}
|
||||
future
|
||||
})
|
||||
|
||||
fun detectVersion(address: InetSocketAddress): CompletableFuture<ProtocolVersion> {
|
||||
return try {
|
||||
SERVER_VER[address]
|
||||
} catch (e: ExecutionException) {
|
||||
mcLogger.warn("Protocol auto detector error: ", e)
|
||||
CompletableFuture.completedFuture(null)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.github.creeper123123321.viaaas.handler.autoprotocol
|
||||
|
||||
import com.github.creeper123123321.viaaas.handler.ConnectionData
|
||||
import com.github.creeper123123321.viaaas.mcLogger
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.channel.ChannelPromise
|
||||
import java.net.InetSocketAddress
|
||||
import java.util.concurrent.TimeUnit
|
||||
import io.netty.channel.ChannelDuplexHandler
|
||||
import java.lang.Exception
|
||||
import java.util.function.Consumer
|
||||
|
||||
// https://github.com/ViaVersion/ViaFabric/blob/mc-1.16/src/main/java/com/github/creeper123123321/viafabric/handler/clientside/ProtocolDetectionHandler.java
|
||||
class ProtocolDetectorHandler(val connectionData: ConnectionData) : ChannelDuplexHandler() {
|
||||
private val queuedMessages = ArrayDeque<Pair<Any, ChannelPromise>>()
|
||||
private var hold = true
|
||||
private var pendentFlush = false
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun channelActive(ctx: ChannelHandlerContext) {
|
||||
super.channelActive(ctx)
|
||||
if (ctx.channel().remoteAddress() is InetSocketAddress) {
|
||||
val timeoutRun = ctx.executor().schedule({
|
||||
mcLogger.warn(
|
||||
"Timeout for protocol auto-detection in "
|
||||
+ ctx.channel().remoteAddress() + " server"
|
||||
)
|
||||
hold = false
|
||||
drainQueue(ctx)
|
||||
ctx.pipeline().remove(this)
|
||||
}, 10, TimeUnit.SECONDS)
|
||||
ProtocolDetector.detectVersion(ctx.channel().remoteAddress() as InetSocketAddress)
|
||||
.whenComplete { protocol, _ ->
|
||||
if (protocol != null && protocol.version != -1) {
|
||||
connectionData.backVer = protocol.version
|
||||
} else {
|
||||
connectionData.backVer = 47 // fallback
|
||||
}
|
||||
|
||||
ctx.pipeline().remove(this)
|
||||
timeoutRun.cancel(false)
|
||||
}
|
||||
// Let's cache it before we need it
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
|
||||
if (!hold) {
|
||||
drainQueue(ctx)
|
||||
super.write(ctx, msg, promise)
|
||||
} else {
|
||||
queuedMessages.add(Pair(msg, promise))
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun flush(ctx: ChannelHandlerContext) {
|
||||
if (!hold) {
|
||||
drainQueue(ctx)
|
||||
super.flush(ctx)
|
||||
} else {
|
||||
pendentFlush = true
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun channelInactive(ctx: ChannelHandlerContext) {
|
||||
drainQueue(ctx)
|
||||
super.channelInactive(ctx)
|
||||
}
|
||||
|
||||
private fun drainQueue(ctx: ChannelHandlerContext) {
|
||||
queuedMessages.forEach(Consumer {
|
||||
ctx.write(
|
||||
it.first,
|
||||
it.second
|
||||
)
|
||||
})
|
||||
queuedMessages.clear()
|
||||
if (pendentFlush) ctx.flush()
|
||||
pendentFlush = false
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun handlerRemoved(ctx: ChannelHandlerContext) {
|
||||
drainQueue(ctx)
|
||||
super.handlerRemoved(ctx)
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ class HandshakeState : MinecraftConnectionState {
|
||||
}
|
||||
|
||||
val parsed = VIAaaSAddress().parse(packet.address.substringBefore(0.toChar()), VIAaaSConfig.hostName)
|
||||
val backProto = parsed.protocol ?: 47 // todo autodetection
|
||||
val backProto = parsed.protocol
|
||||
val hadHostname = parsed.viaSuffix != null
|
||||
|
||||
packet.address = parsed.serverAddress!!
|
||||
@ -61,7 +61,7 @@ class HandshakeState : MinecraftConnectionState {
|
||||
handler.data.backName = parsed.username
|
||||
|
||||
val playerAddr = handler.data.frontHandler.remoteAddress
|
||||
mcLogger.info("Connecting $playerAddr (${handler.data.frontVer}) -> ${packet.address}:${packet.port} ($backProto)")
|
||||
mcLogger.info("Connecting ${handler.data.state.state} $playerAddr (${handler.data.frontVer}) -> ${packet.address}:${packet.port} ($backProto)")
|
||||
|
||||
if (!hadHostname && VIAaaSConfig.requireHostName) {
|
||||
throw UnsupportedOperationException("This VIAaaS instance requires you to use the hostname")
|
||||
|
@ -1,10 +1,18 @@
|
||||
package com.github.creeper123123321.viaaas.handler.state
|
||||
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.packet.UnknownPacket
|
||||
import com.github.creeper123123321.viaaas.config.VIAaaSConfig
|
||||
import com.github.creeper123123321.viaaas.handler.MinecraftHandler
|
||||
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.PluginMessage
|
||||
import com.github.creeper123123321.viaaas.readableToByteArray
|
||||
import io.netty.buffer.ByteBufAllocator
|
||||
import io.netty.buffer.Unpooled
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
import us.myles.ViaVersion.api.type.Type
|
||||
import us.myles.ViaVersion.packets.State
|
||||
|
||||
object PlayState : MinecraftConnectionState {
|
||||
@ -12,10 +20,42 @@ object PlayState : MinecraftConnectionState {
|
||||
get() = State.PLAY
|
||||
|
||||
override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) {
|
||||
if ((packet as UnknownPacket).id !in 0..127) throw IllegalArgumentException("Invalid packet id!")
|
||||
when {
|
||||
packet is UnknownPacket && (packet.id !in 0..127) -> throw IllegalArgumentException("Invalid packet id!")
|
||||
packet is PluginMessage -> modifyPluginMessage(handler, packet)
|
||||
}
|
||||
forward(handler, packet)
|
||||
}
|
||||
|
||||
private fun modifyPluginMessage(handler: MinecraftHandler, pluginMessage: PluginMessage) {
|
||||
when (pluginMessage.channel) {
|
||||
"MC|Brand", "brand", "minecraft:brand" -> {
|
||||
if (!VIAaaSConfig.showBrandInfo) return
|
||||
val brand = if (is1_7(handler)) {
|
||||
String(pluginMessage.data, Charsets.UTF_8)
|
||||
} else {
|
||||
Type.STRING.read(Unpooled.wrappedBuffer(pluginMessage.data))
|
||||
} + " (VIAaaS C: ${ProtocolVersion.getProtocol(handler.data.frontVer!!)} S: ${
|
||||
ProtocolVersion.getProtocol(
|
||||
handler.data.backVer!!
|
||||
)
|
||||
})"
|
||||
|
||||
if (is1_7(handler)) {
|
||||
pluginMessage.data = brand.toByteArray(Charsets.UTF_8)
|
||||
} else {
|
||||
val buf = ByteBufAllocator.DEFAULT.buffer()
|
||||
try {
|
||||
Type.STRING.write(buf, brand)
|
||||
pluginMessage.data = readableToByteArray(buf)
|
||||
} finally {
|
||||
buf.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun disconnect(handler: MinecraftHandler, msg: String) {
|
||||
super.disconnect(handler, msg)
|
||||
handler.data.frontChannel.close()
|
||||
|
@ -1,14 +1,20 @@
|
||||
package com.github.creeper123123321.viaaas.handler.state
|
||||
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusResponse
|
||||
import com.github.creeper123123321.viaaas.packet.UnknownPacket
|
||||
import com.github.creeper123123321.viaaas.config.VIAaaSConfig
|
||||
import com.github.creeper123123321.viaaas.handler.MinecraftHandler
|
||||
import com.github.creeper123123321.viaaas.handler.forward
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.packet.UnknownPacket
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusResponse
|
||||
import com.github.creeper123123321.viaaas.writeFlushClose
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
import us.myles.ViaVersion.packets.State
|
||||
import java.util.*
|
||||
|
||||
object StatusState : MinecraftConnectionState {
|
||||
override val state: State
|
||||
@ -16,9 +22,31 @@ object StatusState : MinecraftConnectionState {
|
||||
|
||||
override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) {
|
||||
if (packet is UnknownPacket) throw IllegalArgumentException("Invalid packet")
|
||||
when (packet) {
|
||||
is StatusResponse -> modifyResponse(handler, packet)
|
||||
}
|
||||
forward(handler, packet)
|
||||
}
|
||||
|
||||
private fun modifyResponse(handler: MinecraftHandler, packet: StatusResponse) {
|
||||
if (VIAaaSConfig.showVersionPing) {
|
||||
val parsed = JsonParser.parseString(packet.json).asJsonObject
|
||||
val players = parsed.getAsJsonObject("players") ?: JsonObject().also { parsed.add("players", it) }
|
||||
val sample = players.getAsJsonArray("sample") ?: JsonArray().also { players.add("sample", it) }
|
||||
sample.add(JsonObject().also {
|
||||
it.addProperty("id", UUID.nameUUIDFromBytes("VIAaaS".toByteArray(Charsets.UTF_8)).toString())
|
||||
it.addProperty(
|
||||
"name",
|
||||
"§9VIAaaS§r (C: §7${ProtocolVersion.getProtocol(handler.data.frontVer!!)}§r S: §7${
|
||||
ProtocolVersion.getProtocol(handler.data.backVer!!)
|
||||
}§r)"
|
||||
)
|
||||
})
|
||||
|
||||
packet.json = parsed.toString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun disconnect(handler: MinecraftHandler, msg: String) {
|
||||
super.disconnect(handler, msg)
|
||||
|
||||
|
@ -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.PluginMessage
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusPing
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusPong
|
||||
import com.github.creeper123123321.viaaas.packet.status.StatusRequest
|
||||
@ -17,6 +18,7 @@ object PacketRegistry {
|
||||
val entries = mutableListOf<RegistryEntry>()
|
||||
|
||||
init {
|
||||
// Obviosly stolen from https://github.com/VelocityPowered/Velocity/blob/dev/1.1.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
|
||||
register(Range.all(), State.HANDSHAKE, 0, true, ::Handshake)
|
||||
register(Range.all(), State.LOGIN, 0, true, ::LoginStart)
|
||||
register(Range.all(), State.LOGIN, 1, true, ::CryptoResponse)
|
||||
@ -25,11 +27,33 @@ object PacketRegistry {
|
||||
register(Range.all(), State.LOGIN, 1, false, ::CryptoRequest)
|
||||
register(Range.all(), State.LOGIN, 2, false, ::LoginSuccess)
|
||||
register(Range.all(), State.LOGIN, 3, false, ::SetCompression)
|
||||
register(Range.all(), State.LOGIN, 4, false, ::PluginRequest)
|
||||
register(Range.atLeast(ProtocolVersion.v1_13.version), State.LOGIN, 4, false, ::PluginRequest)
|
||||
register(Range.all(), State.STATUS, 0, true, ::StatusRequest)
|
||||
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(
|
||||
::PluginMessage, State.PLAY, true, mapOf(
|
||||
Range.closed(ProtocolVersion.v1_7_1.version, ProtocolVersion.v1_8.version) to 0x17,
|
||||
Range.closed(ProtocolVersion.v1_9.version, ProtocolVersion.v1_11_1.version) to 0x09,
|
||||
Range.singleton(ProtocolVersion.v1_12.version) to 0x0A,
|
||||
Range.closed(ProtocolVersion.v1_12_1.version, ProtocolVersion.v1_12_2.version) to 0x09,
|
||||
Range.closed(ProtocolVersion.v1_13.version, ProtocolVersion.v1_13_2.version) to 0x0A,
|
||||
Range.closed(ProtocolVersion.v1_14.version, ProtocolVersion.v1_16_4.version) to 0x0B
|
||||
)
|
||||
)
|
||||
register(
|
||||
::PluginMessage, State.PLAY, false,
|
||||
mapOf(
|
||||
Range.closed(ProtocolVersion.v1_7_1.version, ProtocolVersion.v1_8.version) to 0x3F,
|
||||
Range.closed(ProtocolVersion.v1_9.version, ProtocolVersion.v1_12_2.version) to 0x18,
|
||||
Range.closed(ProtocolVersion.v1_13.version, ProtocolVersion.v1_13_2.version) to 0x19,
|
||||
Range.closed(ProtocolVersion.v1_14.version, ProtocolVersion.v1_14_4.version) to 0x18,
|
||||
Range.closed(ProtocolVersion.v1_15.version, ProtocolVersion.v1_15_2.version) to 0x19,
|
||||
Range.closed(ProtocolVersion.v1_16.version, ProtocolVersion.v1_16_1.version) to 0x18,
|
||||
Range.closed(ProtocolVersion.v1_16_2.version, ProtocolVersion.v1_16_4.version) to 0x17
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
inline fun <reified P : Packet> register(
|
||||
@ -42,6 +66,15 @@ object PacketRegistry {
|
||||
entries.add(RegistryEntry(protocol, state, id, serverBound, constructor, P::class.java))
|
||||
}
|
||||
|
||||
inline fun <reified P : Packet> register(
|
||||
constructor: Supplier<P>,
|
||||
state: State,
|
||||
serverBound: Boolean,
|
||||
idByProtocol: Map<Range<Int>, Int>
|
||||
) {
|
||||
idByProtocol.forEach { (protocol, id) -> register(protocol, state, id, serverBound, constructor) }
|
||||
}
|
||||
|
||||
data class RegistryEntry(
|
||||
val versionRange: Range<Int>,
|
||||
val state: State,
|
||||
@ -63,9 +96,9 @@ object PacketRegistry {
|
||||
}?.constructor
|
||||
}
|
||||
|
||||
fun getPacketId(packetClass: Class<out Packet>, protocolVersion: Int): Int? {
|
||||
fun getPacketId(packetClass: Class<out Packet>, protocolVersion: Int, serverBound: Boolean): Int? {
|
||||
return entries.firstOrNull {
|
||||
it.versionRange.contains(protocolVersion) && it.packetClass == packetClass
|
||||
it.versionRange.contains(protocolVersion) && it.packetClass == packetClass && it.serverBound == serverBound
|
||||
}?.id
|
||||
}
|
||||
|
||||
@ -78,11 +111,11 @@ object PacketRegistry {
|
||||
return packet
|
||||
}
|
||||
|
||||
fun encode(packet: Packet, byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
fun encode(packet: Packet, byteBuf: ByteBuf, protocolVersion: Int, serverBound: Boolean) {
|
||||
val id = if (packet is UnknownPacket) {
|
||||
packet.id
|
||||
} else {
|
||||
getPacketId(packet.javaClass, protocolVersion)!!
|
||||
getPacketId(packet.javaClass, protocolVersion, serverBound)!!
|
||||
}
|
||||
Type.VAR_INT.writePrimitive(byteBuf, id)
|
||||
packet.encode(byteBuf, protocolVersion)
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.github.creeper123123321.viaaas.packet
|
||||
|
||||
import com.github.creeper123123321.viaaas.readableToByteArray
|
||||
import io.netty.buffer.ByteBuf
|
||||
|
||||
class UnknownPacket(val id: Int) : Packet {
|
||||
lateinit var content: ByteArray
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
content = ByteArray(byteBuf.readableBytes()).also { byteBuf.readBytes(it) }
|
||||
content = readableToByteArray(byteBuf)
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.creeper123123321.viaaas.packet.login
|
||||
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.readableToByteArray
|
||||
import io.netty.buffer.ByteBuf
|
||||
import us.myles.ViaVersion.api.type.Type
|
||||
import kotlin.properties.Delegates
|
||||
@ -12,7 +13,7 @@ class PluginRequest : Packet {
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
id = Type.VAR_INT.readPrimitive(byteBuf)
|
||||
channel = Type.STRING.read(byteBuf)
|
||||
data = ByteArray(byteBuf.readableBytes()).also { byteBuf.readBytes(it) }
|
||||
data = readableToByteArray(byteBuf)
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.creeper123123321.viaaas.packet.login
|
||||
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.readableToByteArray
|
||||
import io.netty.buffer.ByteBuf
|
||||
import us.myles.ViaVersion.api.type.Type
|
||||
import kotlin.properties.Delegates
|
||||
@ -13,7 +14,7 @@ class PluginResponse : Packet {
|
||||
id = Type.VAR_INT.readPrimitive(byteBuf)
|
||||
success = byteBuf.readBoolean()
|
||||
if (success) {
|
||||
data = ByteArray(byteBuf.readableBytes()).also { byteBuf.readBytes(it) }
|
||||
data = readableToByteArray(byteBuf)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
package com.github.creeper123123321.viaaas.packet.play
|
||||
|
||||
import com.github.creeper123123321.viaaas.packet.Packet
|
||||
import com.github.creeper123123321.viaaas.readableToByteArray
|
||||
import io.netty.buffer.ByteBuf
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||
import us.myles.ViaVersion.api.type.Type
|
||||
|
||||
class PluginMessage : Packet {
|
||||
lateinit var channel: String
|
||||
lateinit var data: ByteArray
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
channel = Type.STRING.read(byteBuf)
|
||||
data = if (protocolVersion <= ProtocolVersion.v1_7_6.version) {
|
||||
ByteArray(readExtendedForgeShort(byteBuf)).also { byteBuf.readBytes(it) }
|
||||
} else {
|
||||
readableToByteArray(byteBuf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
Type.STRING.write(byteBuf, channel)
|
||||
if (protocolVersion <= ProtocolVersion.v1_7_6.version) {
|
||||
writeExtendedForgeShort(byteBuf, data.size)
|
||||
}
|
||||
byteBuf.writeBytes(data)
|
||||
}
|
||||
|
||||
// stolen from https://github.com/VelocityPowered/Velocity/blob/27ccb9d387fc9a0aecd5c4b570d7d957558efddc/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java#L418
|
||||
fun readExtendedForgeShort(buf: ByteBuf): Int {
|
||||
var low = buf.readUnsignedShort()
|
||||
var high = 0
|
||||
if (low and 0x8000 != 0) {
|
||||
low = low and 0x7FFF
|
||||
high = buf.readUnsignedByte().toInt()
|
||||
}
|
||||
return high and 0xFF shl 15 or low
|
||||
}
|
||||
|
||||
fun writeExtendedForgeShort(buf: ByteBuf, toWrite: Int) {
|
||||
var low = toWrite and 0x7FFF
|
||||
val high = toWrite and 0x7F8000 shr 15
|
||||
if (high != 0) {
|
||||
low = low or 0x8000
|
||||
}
|
||||
buf.writeShort(low)
|
||||
if (high != 0) {
|
||||
buf.writeByte(high)
|
||||
}
|
||||
}
|
||||
}
|
@ -27,4 +27,8 @@ blocked-back-addresses: ["*.hypixel.net", "hypixel.net"]
|
||||
# VIAaaS will only allow if it matches an address in this list
|
||||
allowed-back-addresses: ["*"]
|
||||
# Requires online mode for front-end connections. May be useful for stopping bots.
|
||||
force-online-mode: false
|
||||
force-online-mode: false
|
||||
# Shows player and server version in player list
|
||||
show-version-ping: true
|
||||
# Shows info in server brand (F3)
|
||||
show-brand-info: true
|
Loading…
Reference in New Issue
Block a user