Fix various bugs

This commit is contained in:
Gabriel Tofvesson 2019-04-16 16:24:53 +02:00
parent 182f909cce
commit ba427e0a6f
3 changed files with 53 additions and 60 deletions

@ -1,12 +1,31 @@
import dev.w1zzrd.bungee.BungeeServer import dev.w1zzrd.bungee.BungeeRTCPRouter
import dev.w1zzrd.bungee.BungeeRTCPServer
import java.io.File
import java.net.InetAddress import java.net.InetAddress
import java.nio.file.Files
import java.nio.file.Path
import java.security.KeyFactory
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
fun main(args: Array<String>){ fun main(args: Array<String>){
// Route localhost:80 -> google.com val privKey = KeyFactory.getInstance("RSA")
val server = BungeeServer( .generatePrivate(PKCS8EncodedKeySpec(Files.readAllBytes(Path.of("./private_key.der"))))
InetAddress.getByName("0.0.0.0"), 25565,
InetAddress.getByName("192.168.1.145"), 25565 val pubKey = KeyFactory.getInstance("RSA")
) .generatePublic(X509EncodedKeySpec(Files.readAllBytes(Path.of("./public_key.der"))))
server.start()
server.waitFor() Thread(Runnable {
BungeeRTCPRouter(InetAddress.getByName("0.0.0.0"), 6969, pubKey).listen()
}).start()
Thread.sleep(20)
BungeeRTCPServer(
InetAddress.getByName("0.0.0.0"),
6969,
InetAddress.getByName("192.168.1.145"),
25565,
privKey
).start()
} }

@ -20,7 +20,7 @@ class BungeeRTCPRouter(
private lateinit var routeSocket: Socket private lateinit var routeSocket: Socket
private var alive = false private var alive = false
private var canStart = true private var canStart = true
private val headerBuffer = ByteBuffer.allocateDirect(13) // [ID (byte)][(CUID) long][DLEN (int)] private val headerBuffer = ByteBuffer.wrap(ByteArray(13)) // [ID (byte)][(CUID) long][DLEN (int)]
fun listen(){ fun listen(){
if(!canStart) throw IllegalStateException("Already started/stopped") if(!canStart) throw IllegalStateException("Already started/stopped")
@ -35,7 +35,9 @@ class BungeeRTCPRouter(
val checkBytes = ByteArray(256) val checkBytes = ByteArray(256)
val rand = ThreadLocalRandom.current() val rand = ThreadLocalRandom.current()
val fromClients = ByteArray(BUFFER_SIZE) val fromClients = ByteArray(BUFFER_SIZE)
val wrappedClientBuffer = ByteBuffer.wrap(fromClients)
val fromRoute = ByteArray(BUFFER_SIZE) val fromRoute = ByteArray(BUFFER_SIZE)
val wrappedRouteBuffer = ByteBuffer.wrap(fromRoute)
var routeBytes = 0 var routeBytes = 0
@ -80,9 +82,9 @@ class BungeeRTCPRouter(
} }
// We have a client. Let's check if they can authenticate // We have a client. Let's check if they can authenticate
if(readBytes >= 4 && fromClients.intify(0) == 0x13376969){ // Tell router that you would like to authenticate if(readBytes >= 4 && wrappedClientBuffer.getInt(0) == 0x13376969){ // Tell router that you would like to authenticate
if(readBytes >= (4 + 4)){ if(readBytes >= (4 + 4)){
val signedDataLength = fromClients.intify(4) val signedDataLength = wrappedClientBuffer.getInt(4)
if(readBytes >= (4 + 4 + signedDataLength)){ if(readBytes >= (4 + 4 + signedDataLength)){
// We have the signed data; let's verify its integrity // We have the signed data; let's verify its integrity
@ -92,6 +94,7 @@ class BungeeRTCPRouter(
if(sig.verify(fromClients, 4 + 4, signedDataLength)){ if(sig.verify(fromClients, 4 + 4, signedDataLength)){
// We have a verified remote route! :D // We have a verified remote route! :D
routeSocket = tryRoute!! routeSocket = tryRoute!!
println("RTCP server verified!")
break break
}else{ }else{
// Verification failed :( // Verification failed :(
@ -130,7 +133,7 @@ class BungeeRTCPRouter(
try { try {
val stream = client.getInputStream() val stream = client.getInputStream()
if (stream.available() > 0) { if (stream.available() > 0) {
val read = stream.read(fromClients) val read = stream.read(fromClients, 0, fromClients.size)
if (read > 0 && !sendClientMessageToServer(uid, fromClients, 0, read)) { if (read > 0 && !sendClientMessageToServer(uid, fromClients, 0, read)) {
System.err.println("Unexpected endpoint disconnection") System.err.println("Unexpected endpoint disconnection")
@ -163,21 +166,24 @@ class BungeeRTCPRouter(
// Parse data packet // Parse data packet
if((routeBytes + read) - parsed < 13) break@parseLoop // Not enough data if((routeBytes + read) - parsed < 13) break@parseLoop // Not enough data
val uid = fromRoute.longify(parsed + 1) val uid = wrappedRouteBuffer.getLong(parsed +1)
val dLen = fromRoute.intify(parsed + 1 + 8) val dLen = wrappedRouteBuffer.getInt(parsed + 1 + 8)
if((routeBytes + read) - parsed < 13 + dLen) break@parseLoop // All the data hasn't arrived if((routeBytes + read) - parsed < 13 + dLen) break@parseLoop // All the data hasn't arrived
try {
clients.keys.firstOrNull { clients[it] == uid } clients.keys.firstOrNull { clients[it] == uid }
?.getOutputStream() ?.getOutputStream()
?.write(fromRoute, parsed + 13, dLen) ?.write(fromRoute, parsed + 13, dLen)
}catch(e: Throwable){
notifyClientDisconnect(uid)
}
parsed += 13 + dLen parsed += 13 + dLen
} }
1.toByte() -> { 1.toByte() -> {
// Handle disconnection // Handle disconnection
val uid = fromRoute.longify(parsed + 1) val uid = wrappedRouteBuffer.getLong(parsed + 1)
if(clients.values.contains(uid)){ if(clients.values.contains(uid)){
val toDrop = clients.keys.firstOrNull { clients[it] == uid } val toDrop = clients.keys.firstOrNull { clients[it] == uid }
if(toDrop != null) { if(toDrop != null) {
@ -230,30 +236,3 @@ class BungeeRTCPRouter(
false false
} }
} }
fun ByteArray.intify(offset: Int)
= this[offset].toInt().and(0xFF).or(
this[offset + 1].toInt().and(0xFF).shl(8)
).or(
this[offset + 2].toInt().and(0xFF).shl(16)
).or(
this[offset + 3].toInt().and(0xFF).shl(24)
)
fun ByteArray.longify(offset: Int)
= this[offset].toLong().and(0xFF).or(
this[offset + 1].toLong().and(0xFF).shl(8)
).or(
this[offset + 2].toLong().and(0xFF).shl(16)
).or(
this[offset + 3].toLong().and(0xFF).shl(24)
).or(
this[offset + 4].toLong().and(0xFF).shl(32)
).or(
this[offset + 5].toLong().and(0xFF).shl(40)
).or(
this[offset + 6].toLong().and(0xFF).shl(48)
).or(
this[offset + 7].toLong().and(0xFF).shl(56)
)

@ -22,9 +22,10 @@ class BungeeRTCPServer(
private var canStart = true private var canStart = true
private val serverSocket = Socket() private val serverSocket = Socket()
private val buffer = ByteArray(BUFFER_SIZE) private val buffer = ByteArray(BUFFER_SIZE)
private val wrappedServerBuffer = ByteBuffer.wrap(buffer)
private val clientBuffer = ByteArray(BUFFER_SIZE) private val clientBuffer = ByteArray(BUFFER_SIZE)
private var alive = false private var alive = false
private val headerBuffer = ByteBuffer.allocateDirect(13) private val headerBuffer = ByteBuffer.wrap(ByteArray(13))
fun start(){ fun start(){
if(!canStart) throw IllegalStateException("Already started/stopped") if(!canStart) throw IllegalStateException("Already started/stopped")
@ -42,14 +43,8 @@ class BungeeRTCPServer(
sig.initSign(privateKey) sig.initSign(privateKey)
sig.update(buffer, 0, 256) sig.update(buffer, 0, 256)
val signLen = sig.sign(buffer, 8, buffer.size - 8) val signLen = sig.sign(buffer, 8, buffer.size - 8)
buffer[0] = 0x69.toByte() wrappedServerBuffer.putInt(0, 0x13376969)
buffer[1] = 0x69.toByte() wrappedServerBuffer.putInt(4, signLen)
buffer[2] = 0x37.toByte()
buffer[3] = 0x13.toByte()
buffer[4] = signLen.and(0xFF).toByte()
buffer[5] = signLen.ushr(8).and(0xFF).toByte()
buffer[6] = signLen.ushr(16).and(0xFF).toByte()
buffer[7] = signLen.ushr(24).and(0xFF).toByte()
// Send signature // Send signature
write.write(buffer, 0, 8 + signLen) write.write(buffer, 0, 8 + signLen)
@ -62,7 +57,7 @@ class BungeeRTCPServer(
var parsed = 0 var parsed = 0
parseLoop@while(bufferBytes - parsed > 9){ parseLoop@while(bufferBytes - parsed > 9){
val uid = buffer.longify(parsed + 1) val uid = wrappedServerBuffer.getLong(parsed + 1)
when(buffer[parsed]){ when(buffer[parsed]){
0.toByte() -> { 0.toByte() -> {
@ -73,7 +68,7 @@ class BungeeRTCPServer(
1.toByte() -> { 1.toByte() -> {
// Data from client // Data from client
if(bufferBytes - parsed > 13){ if(bufferBytes - parsed > 13){
val dLen = buffer.intify(parsed + 9) val dLen = wrappedServerBuffer.getInt(parsed + 9)
if(bufferBytes < parsed + dLen) break@parseLoop // Not enough data if(bufferBytes < parsed + dLen) break@parseLoop // Not enough data
try { try {
// Send data to server // Send data to server
@ -104,7 +99,7 @@ class BungeeRTCPServer(
for((uid, client) in vClients){ for((uid, client) in vClients){
try { try {
val stream = client.getInputStream() val stream = client.getInputStream()
if (read.available() > 0) { if (stream.available() > 0) {
val clientRead = stream.read(clientBuffer, 0, clientBuffer.size) val clientRead = stream.read(clientBuffer, 0, clientBuffer.size)
if (clientRead > 0) sendVClientPacket(uid, clientBuffer, 0, clientRead) if (clientRead > 0) sendVClientPacket(uid, clientBuffer, 0, clientRead)
} }
@ -116,7 +111,7 @@ class BungeeRTCPServer(
} }
fun sendVClientPacket(uid: Long, data: ByteArray, off: Int, len: Int){ fun sendVClientPacket(uid: Long, data: ByteArray, off: Int, len: Int){
notifyClientAction(uid, 0, data.size) notifyClientAction(uid, 0, len)
sendMessageToRouter(data, off, len) sendMessageToRouter(data, off, len)
} }
fun notifyClientDrop(uid: Long) = notifyClientAction(uid, 1) fun notifyClientDrop(uid: Long) = notifyClientAction(uid, 1)