mirror of
https://github.com/yggdrasil-network/crispa-android.git
synced 2025-01-22 07:56:30 +00:00
[wip] feat: Implement creating tun interface and starting yggdrasil
This commit is contained in:
parent
ef457d7a9c
commit
e1f412204a
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="io.github.chronosx88.yggdrasil">
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
package="io.github.chronosx88.yggdrasil">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -8,18 +9,27 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme"
|
||||||
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
|
<service
|
||||||
|
android:name=".YggdrasilTunService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true"></service>
|
||||||
<service
|
<service
|
||||||
android:name=".YggdrasilService"
|
android:name=".YggdrasilService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true"
|
||||||
|
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.net.VpnService"/>
|
||||||
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<activity android:name=".MainActivity">
|
<activity android:name=".MainActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
@ -1,12 +1,32 @@
|
|||||||
package io.github.chronosx88.yggdrasil
|
package io.github.chronosx88.yggdrasil
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import android.content.Intent
|
||||||
|
import android.net.VpnService
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
private var isYggStarted = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
val connectButton = findViewById<Button>(R.id.connect_button)
|
||||||
|
connectButton.setOnClickListener {
|
||||||
|
if(!isYggStarted) {
|
||||||
|
VpnService.prepare(this)
|
||||||
|
val intent = Intent(this, YggdrasilTunService::class.java)
|
||||||
|
startService(intent)
|
||||||
|
connectButton.text = "Disconnect"
|
||||||
|
isYggStarted = true
|
||||||
|
} else {
|
||||||
|
val intent = Intent(this, YggdrasilTunService::class.java)
|
||||||
|
stopService(intent)
|
||||||
|
connectButton.text = "Connect"
|
||||||
|
isYggStarted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.chronosx88.yggdrasil
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build.CPU_ABI
|
import android.os.Build.CPU_ABI
|
||||||
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import config.NodeConfig
|
import config.NodeConfig
|
||||||
import io.github.chronosx88.yggdrasil.models.config.Config
|
import io.github.chronosx88.yggdrasil.models.config.Config
|
||||||
@ -37,7 +38,12 @@ fun Context.getYggConfig(): Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Context.generateYggConfig() {
|
fun Context.generateYggConfig() {
|
||||||
execYgg("-genconf > yggdrasil.conf").waitFor()
|
val process = execYgg("-genconf > ${filesDir.absolutePath}/yggdrasil.conf")
|
||||||
|
process.waitFor()
|
||||||
|
val configBytes = process.inputStream.readBytes()
|
||||||
|
val configStr = String(configBytes)
|
||||||
|
val configFile = File(filesDir, "yggdrasil.conf")
|
||||||
|
configFile.writeText(configStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNativeYggConfig(config: Config): NodeConfig {
|
fun createNativeYggConfig(config: Config): NodeConfig {
|
||||||
@ -58,4 +64,36 @@ fun Context.saveYggConfig(config: Config) {
|
|||||||
val configJson = gson.toJson(config)
|
val configJson = gson.toJson(config)
|
||||||
val configFile = File(filesDir, "yggdrasil.conf")
|
val configFile = File(filesDir, "yggdrasil.conf")
|
||||||
configFile.writeText(configJson)
|
configFile.writeText(configJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.installBinary() {
|
||||||
|
val type = "yggdrasil-$YGGDRASIL_VERSION-linux-${CPU_ABI.let {
|
||||||
|
when{
|
||||||
|
it.contains("v8") -> "arm64"
|
||||||
|
it.contains("v7") -> "armhf"
|
||||||
|
else -> throw Exception("Unsupported ABI")
|
||||||
|
}
|
||||||
|
}}"
|
||||||
|
|
||||||
|
yggBin.apply {
|
||||||
|
delete()
|
||||||
|
createNewFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
val input = assets.open(type)
|
||||||
|
val output = yggBin.outputStream()
|
||||||
|
|
||||||
|
try {
|
||||||
|
input.copyTo(output)
|
||||||
|
} finally {
|
||||||
|
input.close(); output.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
yggBin.setExecutable(true)
|
||||||
|
|
||||||
|
val yggConfig = getYggConfig() // it generates config automatically
|
||||||
|
yggConfig.ifName = "tun0"
|
||||||
|
saveYggConfig(yggConfig)
|
||||||
|
|
||||||
|
Log.i("Utils", "# Binary installed successfully")
|
||||||
}
|
}
|
@ -2,8 +2,6 @@ package io.github.chronosx88.yggdrasil
|
|||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build.CPU_ABI
|
|
||||||
import android.util.Log
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
class YggdrasilService : Service() {
|
class YggdrasilService : Service() {
|
||||||
@ -15,38 +13,10 @@ class YggdrasilService : Service() {
|
|||||||
var daemon: Process? = null
|
var daemon: Process? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installBinary() {
|
|
||||||
val type = "yggdrasil-$YGGDRASIL_VERSION-linux-${CPU_ABI.let {
|
|
||||||
when{
|
|
||||||
it.contains("v8") -> "arm64"
|
|
||||||
it.contains("v7") -> "armhf"
|
|
||||||
else -> throw Exception("Unsupported ABI")
|
|
||||||
}
|
|
||||||
}}"
|
|
||||||
|
|
||||||
yggBin.apply {
|
|
||||||
delete()
|
|
||||||
createNewFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
val input = assets.open(type)
|
|
||||||
val output = yggBin.outputStream()
|
|
||||||
|
|
||||||
try {
|
|
||||||
input.copyTo(output)
|
|
||||||
} finally {
|
|
||||||
input.close(); output.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
yggBin.setExecutable(true)
|
|
||||||
generateYggConfig()
|
|
||||||
Log.i(LOG_TAG, "# Binary installed successfully")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun start() {
|
private fun start() {
|
||||||
execYgg("-useconffile yggdrasil.conf").apply {
|
val process = execYgg("-useconffile ${filesDir.absolutePath}/yggdrasil.conf")
|
||||||
daemon = this
|
process.waitFor()
|
||||||
}
|
daemon = process
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stop() {
|
private fun stop() {
|
||||||
@ -66,4 +36,9 @@ class YggdrasilService : Service() {
|
|||||||
}
|
}
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package io.github.chronosx88.yggdrasil
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.VpnService
|
||||||
|
import android.os.ParcelFileDescriptor
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import mobile.Yggdrasil
|
||||||
|
|
||||||
|
|
||||||
|
class YggdrasilTunService : VpnService() {
|
||||||
|
companion object {
|
||||||
|
private var isRunning: Boolean = false
|
||||||
|
}
|
||||||
|
private var tunInterface: ParcelFileDescriptor? = null
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
super.onStartCommand(intent, flags, startId)
|
||||||
|
return Service.START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
isRunning = true
|
||||||
|
setupTunInterface()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupTunInterface() {
|
||||||
|
if(!yggBin.exists()) {
|
||||||
|
installBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = Builder()
|
||||||
|
|
||||||
|
val yggTmp = Yggdrasil()
|
||||||
|
val tempYggConfig = getYggConfig()
|
||||||
|
tempYggConfig.ifName = "none"
|
||||||
|
yggTmp.startJSON(Gson().toJson(tempYggConfig).toByteArray())
|
||||||
|
val address = yggTmp.addressString // hack for getting generic ipv6 string from NodeID
|
||||||
|
|
||||||
|
tunInterface = builder
|
||||||
|
.addAddress(address, 7)
|
||||||
|
.addRoute("0200::", 7)
|
||||||
|
.establish()
|
||||||
|
|
||||||
|
createYggdrasilService()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createYggdrasilService() {
|
||||||
|
val intent = Intent(this, YggdrasilService::class.java)
|
||||||
|
intent.action = "start"
|
||||||
|
startService(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopYggdrasilService() {
|
||||||
|
val intent = Intent(this, YggdrasilService::class.java)
|
||||||
|
stopService(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRevoke() {
|
||||||
|
super.onRevoke()
|
||||||
|
isRunning = false
|
||||||
|
stopYggdrasilService()
|
||||||
|
tunInterface!!.close()
|
||||||
|
tunInterface = null
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
android:id="@+id/connect_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/connect_button"
|
android:text="@string/connect_button"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user