mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2025-02-16 01:41:24 +01:00
code seems cursed, hide websocket error, try to implement allow/block list
This commit is contained in:
parent
fef215f119
commit
a8f75f91bd
@ -19,18 +19,17 @@ import java.util.zip.Deflater
|
|||||||
import java.util.zip.Inflater
|
import java.util.zip.Inflater
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
|
|
||||||
object ChannelInit : ChannelInitializer<Channel>() {
|
object FrontChannelInit : ChannelInitializer<Channel>() {
|
||||||
override fun initChannel(ch: Channel) {
|
override fun initChannel(ch: Channel) {
|
||||||
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"
|
||||||
.addLast("flow-handler", FlowControlHandler())
|
.addLast("flow-handler", FlowControlHandler())
|
||||||
.addLast(
|
.addLast(
|
||||||
"handler", CloudMinecraftHandler(
|
"handler", CloudMinecraftHandler(
|
||||||
ConnectionData(
|
ConnectionData(frontChannel = ch), other = null, frontEnd = true
|
||||||
frontChannel = ch,
|
|
||||||
), other = null, frontEnd = true
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.github.creeper123123321.viaaas
|
package com.github.creeper123123321.viaaas
|
||||||
|
|
||||||
import com.google.common.net.UrlEscapers
|
import com.google.common.net.UrlEscapers
|
||||||
|
import com.google.common.primitives.Ints
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
@ -34,6 +35,7 @@ import javax.crypto.spec.SecretKeySpec
|
|||||||
import javax.naming.NameNotFoundException
|
import javax.naming.NameNotFoundException
|
||||||
import javax.naming.directory.InitialDirContext
|
import javax.naming.directory.InitialDirContext
|
||||||
|
|
||||||
|
|
||||||
val mcLogger = LoggerFactory.getLogger("VIAaaS MC")
|
val mcLogger = LoggerFactory.getLogger("VIAaaS MC")
|
||||||
|
|
||||||
class ConnectionData(
|
class ConnectionData(
|
||||||
@ -89,8 +91,8 @@ class CloudMinecraftHandler(
|
|||||||
|
|
||||||
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
||||||
if (cause is CancelCodecException) return
|
if (cause is CancelCodecException) return
|
||||||
|
mcLogger.info("Exception: ", cause)
|
||||||
disconnect("Exception: $cause")
|
disconnect("Exception: $cause")
|
||||||
mcLogger.debug("Exception: ", cause)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disconnect(s: String) {
|
fun disconnect(s: String) {
|
||||||
@ -154,7 +156,6 @@ class HandshakeState : MinecraftConnectionState {
|
|||||||
|
|
||||||
handler.data.frontChannel.setAutoRead(false)
|
handler.data.frontChannel.setAutoRead(false)
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
val frontHandler = handler.data.frontHandler
|
|
||||||
try {
|
try {
|
||||||
val srvResolved = resolveSrv(packet.address, packet.port)
|
val srvResolved = resolveSrv(packet.address, packet.port)
|
||||||
packet.address = srvResolved.first
|
packet.address = srvResolved.first
|
||||||
@ -162,11 +163,14 @@ class HandshakeState : MinecraftConnectionState {
|
|||||||
|
|
||||||
val socketAddr = InetSocketAddress(InetAddress.getByName(packet.address), packet.port)
|
val socketAddr = InetSocketAddress(InetAddress.getByName(packet.address), packet.port)
|
||||||
|
|
||||||
if (checkLocalAddress(socketAddr.address)) {
|
if (checkLocalAddress(socketAddr.address)
|
||||||
throw SecurityException("Local addresses aren't allowed")
|
|| matchesAddress(socketAddr, VIAaaSConfig.blockedBackAddresses)
|
||||||
|
|| !matchesAddress(socketAddr, VIAaaSConfig.allowedBackAddresses)) {
|
||||||
|
throw SecurityException("Not allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
val bootstrap = Bootstrap().handler(BackendInit(handler.data))
|
val bootstrap = Bootstrap()
|
||||||
|
.handler(BackendInit(handler.data))
|
||||||
.channelFactory(channelSocketFactory())
|
.channelFactory(channelSocketFactory())
|
||||||
.group(handler.data.frontChannel.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
|
||||||
@ -174,24 +178,23 @@ class HandshakeState : MinecraftConnectionState {
|
|||||||
|
|
||||||
bootstrap.addListener {
|
bootstrap.addListener {
|
||||||
if (it.isSuccess) {
|
if (it.isSuccess) {
|
||||||
mcLogger.info("Connected ${frontHandler.remoteAddress} -> $socketAddr")
|
mcLogger.info("Connected ${handler.remoteAddress} -> $socketAddr")
|
||||||
|
|
||||||
val backChan = bootstrap.channel() as SocketChannel
|
val backChan = bootstrap.channel() as SocketChannel
|
||||||
handler.data.backChannel = backChan
|
handler.data.backChannel = backChan
|
||||||
frontHandler.other = backChan
|
handler.other = backChan
|
||||||
|
|
||||||
forward(handler, packet)
|
forward(handler, packet, true)
|
||||||
backChan.flush()
|
|
||||||
|
|
||||||
handler.data.frontChannel.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())
|
handler.disconnect("Couldn't connect: " + it.cause().toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
handler.data.frontChannel.eventLoop().submit {
|
handler.data.frontChannel.eventLoop().submit {
|
||||||
frontHandler.disconnect("Couldn't connect: $e")
|
handler.disconnect("Couldn't connect: $e")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,8 +332,7 @@ object LoginState : MinecraftConnectionState {
|
|||||||
cryptoResponse.encryptedKey = encryptRsa(handler.data.backPublicKey!!, backKey)
|
cryptoResponse.encryptedKey = encryptRsa(handler.data.backPublicKey!!, backKey)
|
||||||
cryptoResponse.encryptedToken =
|
cryptoResponse.encryptedToken =
|
||||||
encryptRsa(handler.data.backPublicKey!!, handler.data.backToken!!)
|
encryptRsa(handler.data.backPublicKey!!, handler.data.backToken!!)
|
||||||
forward(handler, cryptoResponse)
|
forward(handler, cryptoResponse, true)
|
||||||
backChan.flush()
|
|
||||||
|
|
||||||
val backAesEn = mcCfb8(backKey, Cipher.ENCRYPT_MODE)
|
val backAesEn = mcCfb8(backKey, Cipher.ENCRYPT_MODE)
|
||||||
val backAesDe = mcCfb8(backKey, Cipher.DECRYPT_MODE)
|
val backAesDe = mcCfb8(backKey, Cipher.DECRYPT_MODE)
|
||||||
@ -448,11 +450,15 @@ fun generateServerHash(serverId: String, sharedSecret: ByteArray?, key: PublicKe
|
|||||||
return twosComplementHexdigest(digest.digest())
|
return twosComplementHexdigest(digest.digest())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forward(handler: CloudMinecraftHandler, packet: Packet) {
|
private fun forward(handler: CloudMinecraftHandler, packet: Packet, flush: Boolean = false) {
|
||||||
val msg = ByteBufAllocator.DEFAULT.buffer()
|
val msg = ByteBufAllocator.DEFAULT.buffer()
|
||||||
try {
|
try {
|
||||||
PacketRegistry.encode(packet, msg, ProtocolVersion.getProtocol(handler.data.frontVer!!))
|
PacketRegistry.encode(packet, msg, ProtocolVersion.getProtocol(handler.data.frontVer!!))
|
||||||
handler.other!!.write(msg.retain())
|
if (flush) {
|
||||||
|
handler.other!!.writeAndFlush(msg.retain())
|
||||||
|
} else {
|
||||||
|
handler.other!!.write(msg.retain())
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
msg.release()
|
msg.release()
|
||||||
}
|
}
|
||||||
@ -479,4 +485,26 @@ private fun checkLocalAddress(inetAddress: InetAddress): Boolean {
|
|||||||
|| inetAddress.isLoopbackAddress
|
|| inetAddress.isLoopbackAddress
|
||||||
|| inetAddress.isLinkLocalAddress
|
|| inetAddress.isLinkLocalAddress
|
||||||
|| inetAddress.isAnyLocalAddress)
|
|| inetAddress.isAnyLocalAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun matchesAddress(addr: InetSocketAddress, list: List<String>): Boolean {
|
||||||
|
return (matchAddress(addr.hostString, list)
|
||||||
|
|| (addr.address != null && (matchAddress(addr.address.hostAddress, list)
|
||||||
|
|| matchAddress(addr.address.hostName, list))))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun matchAddress(addr: String, list: List<String>): Boolean {
|
||||||
|
if (list.contains("*")) return true
|
||||||
|
val parts = addr.split(".").filter(String::isNotEmpty)
|
||||||
|
val isNumericIp = parts.size == 4 && parts.all { Ints.tryParse(it) != null }
|
||||||
|
return (0..parts.size).any { i: Int ->
|
||||||
|
val query: String = if (isNumericIp) {
|
||||||
|
parts.filterIndexed { it, _ -> it <= i }.joinToString(".") +
|
||||||
|
if (i != 3) ".*" else ""
|
||||||
|
} else {
|
||||||
|
(if (i != 0) "*." else "") +
|
||||||
|
parts.filterIndexed { it, _ -> it >= i }.joinToString(".")
|
||||||
|
}
|
||||||
|
list.contains(query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -127,7 +127,7 @@ fun main(args: Array<String>) {
|
|||||||
val future = ServerBootstrap()
|
val future = ServerBootstrap()
|
||||||
.group(parent, child)
|
.group(parent, child)
|
||||||
.channelFactory(channelServerSocketFactory())
|
.channelFactory(channelServerSocketFactory())
|
||||||
.childHandler(ChannelInit)
|
.childHandler(FrontChannelInit)
|
||||||
.childOption(ChannelOption.IP_TOS, 0x18)
|
.childOption(ChannelOption.IP_TOS, 0x18)
|
||||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||||
.bind(InetAddress.getByName(VIAaaSConfig.bindAddress), VIAaaSConfig.port)
|
.bind(InetAddress.getByName(VIAaaSConfig.bindAddress), VIAaaSConfig.port)
|
||||||
@ -279,6 +279,18 @@ object VIAaaSConfig : Config(File("config/viaaas.yml")) {
|
|||||||
val blockLocalAddress: Boolean get() = this.getBoolean("block-local-address", true)
|
val blockLocalAddress: Boolean get() = this.getBoolean("block-local-address", true)
|
||||||
val requireHostName: Boolean get() = this.getBoolean("require-host-name", true)
|
val requireHostName: Boolean get() = this.getBoolean("require-host-name", true)
|
||||||
val defaultBackendPort: Int get() = this.getInt("default-backend-port", 25565)
|
val defaultBackendPort: Int get() = this.getInt("default-backend-port", 25565)
|
||||||
|
val blockedBackAddresses: List<String>
|
||||||
|
get() = this.get(
|
||||||
|
"blocked-back-addresses",
|
||||||
|
List::class.java,
|
||||||
|
emptyList<String>()
|
||||||
|
)!!.map { it as String }
|
||||||
|
val allowedBackAddresses: List<String>
|
||||||
|
get() = this.get(
|
||||||
|
"allowed-back-addresses",
|
||||||
|
List::class.java,
|
||||||
|
emptyList<String>()
|
||||||
|
)!!.map { it as String }
|
||||||
}
|
}
|
||||||
|
|
||||||
class VIAaaSAddress {
|
class VIAaaSAddress {
|
||||||
|
@ -63,7 +63,7 @@ class ViaWebApp {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
viaWebServer.onException(this, e)
|
viaWebServer.onException(this, e)
|
||||||
this.close(CloseReason(CloseReason.Codes.INTERNAL_ERROR, e.toString()))
|
this.close(CloseReason(CloseReason.Codes.INTERNAL_ERROR, "INTERNAL ERROR"))
|
||||||
} finally {
|
} finally {
|
||||||
viaWebServer.disconnected(this)
|
viaWebServer.disconnected(this)
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,8 @@ block-local-address: true
|
|||||||
require-host-name: true
|
require-host-name: true
|
||||||
# Default port to be used to connect to backend server
|
# Default port to be used to connect to backend server
|
||||||
# Use -1 to reuse the port sent by client, useful for transparent proxying
|
# Use -1 to reuse the port sent by client, useful for transparent proxying
|
||||||
default-backend-port: 25565
|
default-backend-port: 25565
|
||||||
|
# If some server is in this list, it will be blocked. This has priority over allowed-back-addresses
|
||||||
|
blocked-back-addresses: ["*.hypixel.net", "hypixel.net"]
|
||||||
|
# VIAaaS will only allow if it matches an address in this list
|
||||||
|
allowed-back-addresses: ["*"]
|
Loading…
Reference in New Issue
Block a user