package su.sonoma import kotlinx.coroutines.* import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.net.ServerSocket import java.net.Socket import java.io.DataInputStream fun startServer(address: String, port: Int, tun: String, outIntefrace: String) = runBlocking { val tun = TunDevice(address, "awake0") tun.addRoute() tun.enableIpForwarding() tun.enableMasquerade(outIntefrace) val server = ServerSocket(port) println("Server started on $port") while (true) { val client = server.accept() println("${client.inetAddress} Client pairing") launch(Dispatchers.IO) { println("${client.inetAddress} Client connected") try { handle(client, tun) } catch (e: Exception) { e.printStackTrace() } } launch(Dispatchers.IO) { try { forward(client, tun) } catch (e: Exception) { e.printStackTrace() } } } } fun handle(socket: Socket, tun: TunDevice) { val input = BufferedInputStream(socket.getInputStream()) val buffer = ByteArray(1500) while (true) { val hi = input.read() val lo = input.read() if (hi == -1 || lo == -1) { println("${socket.inetAddress} Client disconnected") break } val len = (hi shl 8) or lo //println("Message length: $len") if (len <= 0 || len > buffer.size) { println("Invalid packet size: $len") break } var offset = 0 while (offset < len) { val r = input.read(buffer, offset, len - offset) //println("Read $r from client") if (r == -1) { println("${socket.inetAddress} Client closed stream") return } offset += r } runCatching { tun.output.write(buffer, 0, len) tun.output.flush() } //println("Write in tun") } } fun forward(socket: Socket, tun: TunDevice) { val readBuffer = ByteArray(1500) val output = BufferedOutputStream(socket.getOutputStream()) while (true) { val responseLen = tun.input.read(readBuffer) if (responseLen > 0) { output.write((responseLen shr 8) and 0xFF) output.write(responseLen and 0xFF) output.write(readBuffer, 0, responseLen) output.flush() } } }