first commit
This commit is contained in:
48
src/main/kotlin/Client.kt
Normal file
48
src/main/kotlin/Client.kt
Normal 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
19
src/main/kotlin/Main.kt
Normal 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
66
src/main/kotlin/Server.kt
Normal 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
|
||||
}
|
||||
36
src/main/kotlin/TunDevice.kt
Normal file
36
src/main/kotlin/TunDevice.kt
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user