Tailscale Plugin :D

This commit is contained in:
Alex Zenla 2023-03-19 01:44:06 -07:00
parent 01a520777e
commit 1035c83166
Signed by: alex
GPG Key ID: C0780728420EBFE5
10 changed files with 198 additions and 1 deletions

View File

@ -9,6 +9,7 @@ server.
* foundation-bifrost: Discord chat bridge
* foundation-chaos: Simulate chaos inside a minecraft world
* foundation-heimdall: Event tracking
* foundation-tailscale: Connect the Minecraft Server to Tailscale
## Tools

View File

@ -0,0 +1,20 @@
plugins {
id("gay.pizza.foundation.concrete-plugin")
}
repositories {
maven {
name = "GitLabLibtailscale"
url = uri("https://gitlab.com/api/v4/projects/44435887/packages/maven")
}
}
dependencies {
implementation(project(":common-plugin"))
compileOnly(project(":foundation-shared"))
implementation(libs.tailscale)
}
concreteItem {
dependency(project(":foundation-core"))
}

View File

@ -0,0 +1,30 @@
package gay.pizza.foundation.tailscale
import com.charleskorn.kaml.Yaml
import gay.pizza.foundation.common.BaseFoundationPlugin
import gay.pizza.foundation.common.FoundationCoreLoader
import gay.pizza.foundation.shared.PluginMainClass
import gay.pizza.foundation.shared.copyDefaultConfig
import kotlin.io.path.inputStream
@PluginMainClass
class FoundationTailscalePlugin : BaseFoundationPlugin() {
lateinit var config: TailscaleConfig
lateinit var controller: TailscaleController
override fun onEnable() {
val foundation = FoundationCoreLoader.get(server)
val configPath = copyDefaultConfig<FoundationTailscalePlugin>(
slF4JLogger,
foundation.pluginDataPath,
"tailscale.yaml"
)
config = Yaml.default.decodeFromStream(TailscaleConfig.serializer(), configPath.inputStream())
controller = TailscaleController(server, config)
controller.enable()
}
override fun onDisable() {
controller.disable()
}
}

View File

@ -0,0 +1,13 @@
package gay.pizza.foundation.tailscale
import kotlinx.serialization.Serializable
@Serializable
data class TailscaleConfig(
val enabled: Boolean = false,
val hostname: String,
val controlUrl: String? = null,
val authKey: String? = null,
val tailscalePath: String? = null,
val ephemeral: Boolean = false
)

View File

@ -0,0 +1,38 @@
package gay.pizza.foundation.tailscale
import gay.pizza.tailscale.core.Tailscale
import org.bukkit.Server
class TailscaleController(val server: Server, val config: TailscaleConfig) {
private val tailscale = Tailscale()
var tailscaleProxyServer: TailscaleProxyServer? = null
fun enable() {
if (!config.enabled) {
return
}
tailscale.hostname = config.hostname
if (config.controlUrl != null) {
tailscale.controlUrl = config.controlUrl
}
if (config.authKey != null) {
tailscale.authKey = config.authKey
}
if (config.tailscalePath != null) {
tailscale.directoryPath = config.tailscalePath
}
tailscale.up()
tailscaleProxyServer = TailscaleProxyServer(server, tailscale)
tailscaleProxyServer?.listen()
}
fun disable() {
tailscaleProxyServer?.close()
tailscale.close()
}
}

View File

@ -0,0 +1,70 @@
package gay.pizza.foundation.tailscale
import gay.pizza.tailscale.core.Tailscale
import gay.pizza.tailscale.core.TailscaleConn
import gay.pizza.tailscale.core.TailscaleListener
import org.bukkit.Server
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.ClosedChannelException
import java.nio.channels.ReadableByteChannel
import java.nio.channels.SocketChannel
import java.nio.channels.WritableByteChannel
class TailscaleProxyServer(val server: Server, val tailscale: Tailscale) {
private var minecraftServerListener: TailscaleListener? = null
fun listen() {
minecraftServerListener?.close()
minecraftServerListener = tailscale.listen("tcp", ":25565")
val thread = Thread {
minecraftServerListener?.threadedAcceptLoop { conn ->
handleServerConnection(conn)
}
}
thread.name = "Tailscale Accept Loop"
thread.start()
}
fun handleServerConnection(conn: TailscaleConn) {
val socketChannel = SocketChannel.open(InetSocketAddress("127.0.0.1", server.port))
val connChannel = conn.openReadWriteChannel()
fun closeAll() {
socketChannel.close()
connChannel.close()
}
fun startCopyThread(name: String, from: ReadableByteChannel, to: WritableByteChannel) {
val thread = Thread {
try {
while (from.isOpen && to.isOpen) {
val buffer = ByteBuffer.allocate(2048)
val size = from.read(buffer)
if (size < 0) {
break
} else {
buffer.flip()
val array = buffer.array()
to.write(buffer)
}
buffer.clear()
}
} catch (_: ClosedChannelException) {
} finally {
closeAll()
}
}
thread.name = name
thread.start()
}
startCopyThread("Tailscale to Socket Pipe", connChannel, socketChannel)
startCopyThread("Socket to Tailscale Pipe", socketChannel, connChannel)
}
fun close() {
minecraftServerListener?.close()
}
}

View File

@ -0,0 +1,11 @@
name: Foundation-Tailscale
version: '${version}'
main: gay.pizza.foundation.tailscale.FoundationTailscalePlugin
api-version: 1.18
prefix: Foundation-Tailscale
load: STARTUP
depend:
- Foundation
authors:
- kubeliv
- azenla

View File

@ -0,0 +1,12 @@
# Whether Tailscale is enabled.
enabled: false
# Hostname for Tailscale node.
hostname: minecraft
# Tailscale control URL. Null for the default.
controlUrl: null
# Tailscale authentication key. Null for the default.
authKey: null
# Tailscale path. Null for the default.
tailscalePath: null
# Tailscale ephemeral mode.
ephemeral: false

View File

@ -41,4 +41,3 @@ do
# Download the plugin and store it at the mentioned path.
curl --fail -Ls "$base_url/$artifact_path" --output "$dl_path" || (echo "Failed to download ${artifact_path}"; exit 1)
done

View File

@ -33,6 +33,7 @@ include(
":foundation-bifrost",
":foundation-chaos",
":foundation-heimdall",
":foundation-tailscale",
":tool-gjallarhorn",
)
@ -72,6 +73,7 @@ dependencyResolutionManagement {
version("postgresql", "42.5.3")
version("exposed", "0.41.1")
version("hikaricp", "5.0.1")
version("libtailscale", "0.1.2-SNAPSHOT")
library("clikt", "com.github.ajalt.clikt", "clikt").versionRef("clikt")
library("xodus-core", "org.jetbrains.xodus", "xodus-openAPI").versionRef("xodus")
@ -90,6 +92,7 @@ dependencyResolutionManagement {
library("exposed-jdbc", "org.jetbrains.exposed", "exposed-jdbc").versionRef("exposed")
library("exposed-java-time", "org.jetbrains.exposed", "exposed-java-time").versionRef("exposed")
library("hikaricp", "com.zaxxer", "HikariCP").versionRef("hikaricp")
library("tailscale", "gay.pizza.tailscale", "tailscale").versionRef("libtailscale")
}
}
}