1. VPN DNS refactoring, GUI refactoring

This commit is contained in:
vadym 2020-06-28 04:55:48 -07:00
parent 50a107cea4
commit 63f777d2c4
7 changed files with 284 additions and 232 deletions

View File

@ -12,7 +12,6 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".PeerListActivity"
@ -35,6 +34,8 @@
</service>
<activity android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -10,8 +10,6 @@ import android.net.VpnService
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
@ -34,6 +32,7 @@ class MainActivity : AppCompatActivity() {
const val COMMAND = "COMMAND"
const val STOP = "STOP"
const val START = "START"
const val UPDATE_DNS = "UPDATE_DNS"
const val PARAM_PINTENT = "pendingIntent"
const val STATUS_START = 7
const val STATUS_FINISH = 8
@ -52,6 +51,7 @@ class MainActivity : AppCompatActivity() {
private const val VPN_REQUEST_CODE = 0x0F
@JvmStatic var isStarted = false
@JvmStatic var isCancelled = false
}
@ -62,19 +62,41 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(findViewById(R.id.toolbar))
if(intent.extras!==null) {
startVpnFlag = intent.extras!!.getBoolean(START_VPN, false)
isStarted = true
//startVpn()
} else {
isStarted = isYggServiceRunning(this)
}
val listView = findViewById<ListView>(R.id.peers)
val switchOn = findViewById<Switch>(R.id.switchOn)
switchOn.isChecked = isStarted
switchOn.setOnCheckedChangeListener { _, isChecked ->
if(currentPeers.isEmpty()){
switchOn.isChecked = false
return@setOnCheckedChangeListener
}
if(isCancelled){
switchOn.isChecked = false
isCancelled = false
return@setOnCheckedChangeListener
}
if (isChecked) {
startVpn()
} else {
stopVpn()
}
}
val peersListView = findViewById<ListView>(R.id.peers)
//save to shared preferences
val preferences =
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
currentPeers = deserializeStringSet2PeerInfoSet(preferences.getStringSet(CURRENT_PEERS, HashSet())!!)
val adapter = PeerInfoListAdapter(this, currentPeers.sortedWith(compareBy { it.ping }))
listView.adapter = adapter
peersListView.adapter = adapter
val copyAddressButton = findViewById<Button>(R.id.copyIp)
copyAddressButton.setOnClickListener {
@ -133,6 +155,17 @@ class MainActivity : AppCompatActivity() {
}
}
private fun updateDNS(){
Log.d(TAG,"Update DNS")
val intent = Intent(this, YggdrasilTunService::class.java)
val TASK_CODE = 100
val pi = createPendingResult(TASK_CODE, intent, 0)
intent.putExtra(PARAM_PINTENT, pi)
intent.putExtra(COMMAND, UPDATE_DNS)
intent.putStringArrayListExtra(DNS, serializeDNSInfoSet2StringList(currentDNS))
startService(intent)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
@ -151,7 +184,7 @@ class MainActivity : AppCompatActivity() {
startService(intent)
}
if (requestCode == VPN_REQUEST_CODE && resultCode== Activity.RESULT_CANCELED){
//TODO implement
isCancelled = true
}
if (requestCode == PEER_LIST_CODE && resultCode== Activity.RESULT_OK){
if(data!!.extras!=null){
@ -197,15 +230,7 @@ class MainActivity : AppCompatActivity() {
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
preferences.edit().putStringSet(CURRENT_DNS, HashSet(currentDNS)).apply()
if(isStarted){
//TODO implement UpdateConfig method in native interface and apply peer changes
stopVpn()
finish()
val i = baseContext.packageManager
.getLaunchIntentForPackage(baseContext.packageName)
i!!.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
i.putExtra(START_VPN, true)
startActivity(i)
updateDNS()
}
}
}
@ -231,34 +256,6 @@ class MainActivity : AppCompatActivity() {
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main_menu, menu)
val item = menu.findItem(R.id.switchId) as MenuItem
item.setActionView(R.layout.menu_switch)
val switchOn = item
.actionView.findViewById<Switch>(R.id.switchOn)
if(isStarted){
switchOn.isChecked = true
if(startVpnFlag) {
startVpn()
}
}
switchOn.setOnCheckedChangeListener { _, isChecked ->
if(currentPeers.isEmpty()){
switchOn.isChecked = false
return@setOnCheckedChangeListener
}
if (isChecked) {
startVpn()
} else {
stopVpn()
}
}
return true
}
private fun showToast(text: String){
val duration = Toast.LENGTH_SHORT
val toast = Toast.makeText(applicationContext, text, duration)

View File

@ -10,6 +10,7 @@ import com.google.gson.Gson
import dummy.ConduitEndpoint
import io.github.chronosx88.yggdrasil.models.DNSInfo
import io.github.chronosx88.yggdrasil.models.PeerInfo
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.convertPeerInfoSet2PeerIdSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet
import kotlinx.coroutines.*
@ -29,20 +30,12 @@ class YggdrasilTunService : VpnService() {
companion object {
private const val TAG = "Yggdrasil-service"
@JvmStatic
fun convertPeerInfoSet2PeerIdSet(list: Set<PeerInfo>): Set<String> {
var out = mutableSetOf<String>()
for(p in list) {
out.add(p.toString())
}
return out
}
}
private var tunInterface: ParcelFileDescriptor? = null
private var tunInputStream: InputStream? = null
private var tunOutputStream: OutputStream? = null
private var scope: CoroutineScope? = null
private var address: String? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@ -57,10 +50,37 @@ class YggdrasilTunService : VpnService() {
ygg = Yggdrasil()
setupTunInterface(pi, peers, dns)
}
if (intent?.getStringExtra(MainActivity.COMMAND) == MainActivity.UPDATE_DNS) {
val pi: PendingIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT)
val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS))
setupIOStreams(dns)
}
return super.onStartCommand(intent, flags, startId)
}
private fun setupIOStreams(dns: MutableSet<DNSInfo>){
address = ygg.addressString
var builder = Builder()
.addAddress(address, 7)
.allowFamily(OsConstants.AF_INET)
.setMtu(MAX_PACKET_SIZE)
if (dns.size > 0) {
for (d in dns) {
builder.addDnsServer(d.address)
}
}
if(tunInterface!=null){
tunInterface!!.close()
tunInputStream!!.close()
tunOutputStream!!.close()
}
tunInterface = builder.establish()
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
}
private fun setupTunInterface(
pi: PendingIntent,
peers: Set<PeerInfo>,
@ -74,31 +94,15 @@ class YggdrasilTunService : VpnService() {
configJson = gson.toJson(config).toByteArray()
var yggConduitEndpoint = ygg.startJSON(configJson)
val address = ygg.addressString // hack for getting generic ipv6 string from NodeID
var builder = Builder()
.addAddress(address, 7)
.allowFamily(OsConstants.AF_INET)
.setMtu(MAX_PACKET_SIZE)
if (dns.size > 0) {
for (d in dns) {
builder.addDnsServer(d.address)
}
}
tunInterface = builder.establish()
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
setupIOStreams(dns)
val job = SupervisorJob()
scope = CoroutineScope(Dispatchers.Default + job)
scope!!.launch {
val buffer = ByteArray(2048)
try {
while (!isClosed) {
readPacketsFromTun(yggConduitEndpoint, buffer)
}
} catch (e: IOException) {
e.printStackTrace()
tunInputStream!!.close()
while (!isClosed) {
readPacketsFromTun(yggConduitEndpoint, buffer)
}
}
scope!!.launch {
@ -144,25 +148,27 @@ class YggdrasilTunService : VpnService() {
private fun readPacketsFromTun(yggConduitEndpoint: ConduitEndpoint, buffer: ByteArray) {
// Read the outgoing packet from the input stream.
val length = tunInputStream!!.read(buffer)
if (length > 0) {
val byteBuffer = ByteBuffer.allocate(length)
byteBuffer.put(buffer, 0, length)
yggConduitEndpoint.send(byteBuffer.array())
} else {
Thread.sleep(10)
try{
val length = tunInputStream!!.read(buffer)
if (length > 0) {
val byteBuffer = ByteBuffer.allocate(length)
byteBuffer.put(buffer, 0, length)
yggConduitEndpoint.send(byteBuffer.array())
} else {
Thread.sleep(10)
}
}catch(e: IOException){
e.printStackTrace()
}
}
private fun writePacketsToTun(yggConduitEndpoint: ConduitEndpoint) {
if(tunOutputStream != null) {
val buffer = yggConduitEndpoint.recv()
if(buffer!=null) {
try {
tunOutputStream!!.write(buffer)
}catch(e: IOException){
e.printStackTrace()
}
val buffer = yggConduitEndpoint.recv()
if(buffer!=null) {
try {
tunOutputStream!!.write(buffer)
}catch(e: IOException){
e.printStackTrace()
}
}
}

View File

@ -86,5 +86,14 @@ class Utils {
return (System.currentTimeMillis() - start).toInt()
}
@JvmStatic
fun convertPeerInfoSet2PeerIdSet(list: Set<PeerInfo>): Set<String> {
var out = mutableSetOf<String>()
for(p in list) {
out.add(p.toString())
}
return out
}
}
}

View File

@ -1,158 +1,48 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey"
tools:context=".MainActivity">
tools:context=".MainActivity"
android:background="@color/grey">
<LinearLayout
android:id="@+id/ipLayout"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/info_panel_rounded_corner"
android:gravity="left"
android:paddingLeft="20dp"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
android:animateLayoutChanges="true"
android:visibility="gone">
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/ipLabel"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
android:text="IP address:"
android:layout_height="?attr/actionBarSize"
android:layout_marginEnd="70dp"
android:background="?attr/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="@color/dark_30"
/>
<Button
android:id="@+id/copyIp"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<Switch
android:id="@+id/switchOn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="COPY"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:theme="@style/SwitchTheme"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/ip"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/copyIp"
android:text=""
android:textColor="@color/white"/>
</LinearLayout>
<LinearLayout
android:id="@+id/peerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/info_panel_rounded_corner"
android:gravity="left"
android:paddingLeft="20dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/ipLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/ipPeers"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
android:text="Peers:"
android:textColor="@color/dark_30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/edit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="EDIT"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ListView
android:id="@+id/peers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginBottom="10dp"
android:dividerHeight="0dp"
android:divider="@null"
app:layout_constraintTop_toTopOf="parent"/>
</com.google.android.material.appbar.AppBarLayout>
</LinearLayout>
<include layout="@layout/content_main" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/info_panel_rounded_corner"
android:gravity="left"
android:paddingLeft="20dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/peerLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/dnsLabel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
android:text="DNS:"
android:textColor="@color/dark_30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/editDNS"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="EDIT"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ListView
android:id="@+id/dns"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginBottom="10dp"
android:dividerHeight="0dp"
android:divider="@null"
app:layout_constraintTop_toTopOf="parent"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,156 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:background="@color/grey">
<LinearLayout
android:id="@+id/ipLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/info_panel_rounded_corner"
android:gravity="left"
android:paddingLeft="20dp"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
android:animateLayoutChanges="true"
android:visibility="gone">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/ipLabel"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
android:text="IP address:"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="@color/dark_30"
/>
<Button
android:id="@+id/copyIp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="COPY"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/ip"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/copyIp"
android:text=""
android:textColor="@color/white"/>
</LinearLayout>
<LinearLayout
android:id="@+id/peerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/info_panel_rounded_corner"
android:gravity="left"
android:paddingLeft="20dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/ipLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/ipPeers"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
android:text="Peers:"
android:textColor="@color/dark_30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/edit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="EDIT"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ListView
android:id="@+id/peers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginBottom="10dp"
android:dividerHeight="0dp"
android:divider="@null"
app:layout_constraintTop_toTopOf="parent"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/info_panel_rounded_corner"
android:gravity="left"
android:paddingLeft="20dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/peerLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/dnsLabel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:elevation="8dp"
android:gravity="center_vertical"
android:text="DNS:"
android:textColor="@color/dark_30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/editDNS"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="EDIT"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ListView
android:id="@+id/dns"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginBottom="10dp"
android:dividerHeight="0dp"
android:divider="@null"
app:layout_constraintTop_toTopOf="parent"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,12 +3,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Switch
android:id="@+id/switchOn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:theme="@style/SwitchTheme"/>
</RelativeLayout>