first commit

This commit is contained in:
2026-05-24 21:15:44 +03:00
parent ea2cf48281
commit 544624ea0c
18 changed files with 640 additions and 0 deletions

48
src/main/kotlin/Client.kt Normal file
View File

@ -0,0 +1,48 @@
package su.sonoma
import kotlinx.coroutines.*
import java.io.DataInputStream
import java.net.Socket
fun startClient() = runBlocking {
val tun = TunDevice()
val socket = Socket("192.168.88.228", 9093)
val input = socket.getInputStream()
val output = socket.getOutputStream()
println("Client started")
launch {
val buffer = ByteArray(32768)
// TUN → SERVER
while (true) {
val len = tun.input.read(buffer)
if (len > 0) {
output.write(len shr 8)
output.write(len)
output.write(buffer, 0, len)
}
}
}
launch {
val buffer = ByteArray(32768)
// SERVER → TUN
while (true) {
val hi = input.read()
val lo = input.read()
val len = (hi shl 8) or lo
DataInputStream(input).readFully(buffer, 0, len)
tun.output.write(buffer, 0, len)
}
}
}

19
src/main/kotlin/Main.kt Normal file
View File

@ -0,0 +1,19 @@
package su.sonoma
import io.ktor.network.selector.*
import io.ktor.network.sockets.*
import io.ktor.utils.io.*
import io.ktor.utils.io.core.readBytes
import kotlinx.coroutines.*
import kotlinx.io.readByteArray
import java.io.FileInputStream
fun main(args: Array<String>) {
when (args.firstOrNull()) {
"server" -> startServer()
"client" -> startClient()
else -> {
println("Usage: server | client")
}
}
}

66
src/main/kotlin/Server.kt Normal file
View File

@ -0,0 +1,66 @@
package su.sonoma
import kotlinx.coroutines.*
import java.net.ServerSocket
import java.net.Socket
import java.io.InputStream
import java.io.DataInputStream
fun startServer() = runBlocking {
val server = ServerSocket(9093)
println("Server started")
while (true) {
val client = server.accept()
launch {
handle(client)
}
}
}
suspend fun handle(socket: Socket) {
val input = socket.getInputStream()
val output = socket.getOutputStream()
val buffer = ByteArray(32768)
while (true) {
val hi = input.read()
val lo = input.read()
val len = (hi shl 8) or lo
DataInputStream(input).readFully(buffer, 0, len)
val packet = buffer.copyOf(len)
// 🌍 forward to internet
val response = forwardPacket(packet)
output.write(response.size shr 8)
output.write(response.size)
output.write(response)
}
}
fun forwardPacket(packet: ByteArray): ByteArray {
// ⚠️ simplified: we assume HTTP (not real VPN parsing yet)
val host = "example.com"
val port = 80
val socket = Socket(host, port)
socket.getOutputStream().write(packet)
val response = socket.getInputStream().readBytes()
socket.close()
return response
}

View File

@ -0,0 +1,36 @@
package su.sonoma
import java.io.FileDescriptor
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.RandomAccessFile
class TunDevice(
private val name: String = "tun0"
) {
val input: FileInputStream
val output: FileOutputStream
init {
val fd = openTun(name)
input = FileInputStream(fd)
output = FileOutputStream(fd)
}
private fun openTun(name: String): java.io.FileDescriptor {
val fd = java.io.FileDescriptor()
val tun = RandomAccessFile("/dev/net/tun", "rw")
val field = tun.javaClass.getDeclaredField("fd")
field.isAccessible = true
val flags = 0x0001 or 0x1000
val ioctl = ioctlTun(tun.fd, name, flags)
if (ioctl < 0) error("Cannot open TUN")
return tun.fd
}
private external fun ioctlTun(fd: FileDescriptor?, name: String, flags: Int): Int
}