[wip] feat: Implement creating tun interface and starting yggdrasil

This commit is contained in:
ChronosX88 2019-08-26 19:16:57 +04:00
parent ef457d7a9c
commit e1f412204a
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
6 changed files with 151 additions and 40 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<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
android:allowBackup="true"
@ -8,18 +9,27 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
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
android:name=".YggdrasilService"
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>
<activity android:name=".MainActivity">
<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>
</activity>
</application>

View File

@ -1,12 +1,32 @@
package io.github.chronosx88.yggdrasil
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.net.VpnService
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private var isYggStarted = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
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
}
}
}
}

View File

@ -2,6 +2,7 @@ package io.github.chronosx88.yggdrasil
import android.content.Context
import android.os.Build.CPU_ABI
import android.util.Log
import com.google.gson.Gson
import config.NodeConfig
import io.github.chronosx88.yggdrasil.models.config.Config
@ -37,7 +38,12 @@ fun Context.getYggConfig(): Config {
}
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 {
@ -58,4 +64,36 @@ fun Context.saveYggConfig(config: Config) {
val configJson = gson.toJson(config)
val configFile = File(filesDir, "yggdrasil.conf")
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")
}

View File

@ -2,8 +2,6 @@ package io.github.chronosx88.yggdrasil
import android.app.Service
import android.content.Intent
import android.os.Build.CPU_ABI
import android.util.Log
import kotlin.system.exitProcess
class YggdrasilService : Service() {
@ -15,38 +13,10 @@ class YggdrasilService : Service() {
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() {
execYgg("-useconffile yggdrasil.conf").apply {
daemon = this
}
val process = execYgg("-useconffile ${filesDir.absolutePath}/yggdrasil.conf")
process.waitFor()
daemon = process
}
private fun stop() {
@ -66,4 +36,9 @@ class YggdrasilService : Service() {
}
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
stop()
}
}

View File

@ -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
}
}

View File

@ -9,6 +9,7 @@
android:gravity="center">
<Button
android:id="@+id/connect_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/connect_button"