1. added peers update in Mesh mode

This commit is contained in:
vadym 2020-07-01 01:53:34 -07:00
parent e597fff59b
commit bca4b88d3d
6 changed files with 159 additions and 15 deletions

View File

@ -2,10 +2,7 @@ package io.github.chronosx88.yggdrasil
import android.app.Activity import android.app.Activity
import android.app.ActivityManager import android.app.ActivityManager
import android.content.ClipData import android.content.*
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.VpnService import android.net.VpnService
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@ -18,17 +15,26 @@ import io.github.chronosx88.yggdrasil.models.DNSInfo
import io.github.chronosx88.yggdrasil.models.PeerInfo import io.github.chronosx88.yggdrasil.models.PeerInfo
import io.github.chronosx88.yggdrasil.models.config.DNSInfoListAdapter import io.github.chronosx88.yggdrasil.models.config.DNSInfoListAdapter
import io.github.chronosx88.yggdrasil.models.config.PeerInfoListAdapter import io.github.chronosx88.yggdrasil.models.config.PeerInfoListAdapter
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializePeerStringList2PeerInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringSet2DNSInfoSet import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringSet2DNSInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringSet2PeerInfoSet import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringSet2PeerInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.serializeDNSInfoSet2StringList import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.serializeDNSInfoSet2StringList
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.serializePeerInfoSet2StringList import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.serializePeerInfoSet2StringList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.InetAddress
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
companion object { companion object {
const val STATUS_PEERS_UPDATE = 12
const val MESH_PEERS = "MESH_PEERS"
const val STATIC_IP = "STATIC_IP_FLAG" const val STATIC_IP = "STATIC_IP_FLAG"
const val signingPrivateKey = "signingPrivateKey" const val signingPrivateKey = "signingPrivateKey"
const val signingPublicKey = "signingPublicKey" const val signingPublicKey = "signingPublicKey"
@ -38,6 +44,7 @@ class MainActivity : AppCompatActivity() {
const val STOP = "STOP" const val STOP = "STOP"
const val START = "START" const val START = "START"
const val UPDATE_DNS = "UPDATE_DNS" const val UPDATE_DNS = "UPDATE_DNS"
const val UPDATE_PEERS = "UPDATE_PEERS"
const val PARAM_PINTENT = "pendingIntent" const val PARAM_PINTENT = "pendingIntent"
const val STATUS_START = 7 const val STATUS_START = 7
const val STATUS_FINISH = 8 const val STATUS_FINISH = 8
@ -49,7 +56,7 @@ class MainActivity : AppCompatActivity() {
const val DNS_LIST_CODE = 2000 const val DNS_LIST_CODE = 2000
const val PEER_LIST = "PEERS_LIST" const val PEER_LIST = "PEERS_LIST"
const val DNS_LIST = "DNS_LIST" const val DNS_LIST = "DNS_LIST"
const val CURRENT_PEERS = "CURRENT_PEERS_v1.2" const val CURRENT_PEERS = "CURRENT_PEERS_v1.2.1"
const val CURRENT_DNS = "CURRENT_DNS_v1.2" const val CURRENT_DNS = "CURRENT_DNS_v1.2"
const val START_VPN = "START_VPN" const val START_VPN = "START_VPN"
private const val TAG="Yggdrasil" private const val TAG="Yggdrasil"
@ -62,6 +69,7 @@ class MainActivity : AppCompatActivity() {
private var currentPeers = setOf<PeerInfo>() private var currentPeers = setOf<PeerInfo>()
private var currentDNS = setOf<DNSInfo>() private var currentDNS = setOf<DNSInfo>()
private var meshPeersReceiver: BroadcastReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -169,6 +177,16 @@ class MainActivity : AppCompatActivity() {
startService(intent) startService(intent)
} }
private fun updatePeers(){
Log.d(TAG,"Update Peers")
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_PEERS)
startService(intent)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
@ -244,7 +262,20 @@ class MainActivity : AppCompatActivity() {
} }
when (resultCode) { when (resultCode) {
STATUS_START -> print("service started") STATUS_START -> {
print("service started")
if(this.currentPeers.isEmpty()){
//this is Mesh mode, send Peers update every 5 sec
thread(start = true) {
while(true) {
Thread.sleep(5000)
if(isStarted) {
updatePeers()
}
}
}
}
}
STATUS_FINISH -> { STATUS_FINISH -> {
isStarted = true isStarted = true
val ipLayout = findViewById<LinearLayout>(R.id.ipLayout) val ipLayout = findViewById<LinearLayout>(R.id.ipLayout)
@ -257,6 +288,23 @@ class MainActivity : AppCompatActivity() {
val ipLayout = findViewById<LinearLayout>(R.id.ipLayout) val ipLayout = findViewById<LinearLayout>(R.id.ipLayout)
ipLayout.visibility = View.GONE ipLayout.visibility = View.GONE
} }
STATUS_PEERS_UPDATE ->{
if(data!!.extras!=null) {
thread(start = true) {
val meshPeers = deserializePeerStringList2PeerInfoSet(
data.extras!!.getStringArrayList(MESH_PEERS)
)
val listView = findViewById<ListView>(R.id.peers)
val adapter = PeerInfoListAdapter(
this@MainActivity,
meshPeers.sortedWith(compareBy { it.ping })
)
runOnUiThread {
listView.adapter = adapter
}
}
}
}
else -> { // Note the block else -> { // Note the block
} }
@ -290,4 +338,11 @@ class MainActivity : AppCompatActivity() {
preferences.getString(STATIC_IP, null) != null preferences.getString(STATIC_IP, null) != null
} }
override fun onDestroy() {
super.onDestroy()
if (meshPeersReceiver != null){
unregisterReceiver(meshPeersReceiver);
}
}
} }

View File

@ -16,9 +16,12 @@ import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import dummy.ConduitEndpoint import dummy.ConduitEndpoint
import io.github.chronosx88.yggdrasil.models.DNSInfo import io.github.chronosx88.yggdrasil.models.DNSInfo
import io.github.chronosx88.yggdrasil.models.PeerInfo import io.github.chronosx88.yggdrasil.models.PeerInfo
import io.github.chronosx88.yggdrasil.models.config.Peer
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.convertPeer2PeerStringList
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.convertPeerInfoSet2PeerIdSet 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.deserializeStringList2DNSInfoSet
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet
@ -27,6 +30,7 @@ import mobile.Mobile
import mobile.Yggdrasil import mobile.Yggdrasil
import java.io.* import java.io.*
import java.net.Inet6Address import java.net.Inet6Address
import kotlin.concurrent.thread
class YggdrasilTunService : VpnService() { class YggdrasilTunService : VpnService() {
@ -56,10 +60,9 @@ class YggdrasilTunService : VpnService() {
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val pi: PendingIntent? = intent?.getParcelableExtra(MainActivity.PARAM_PINTENT)
when(intent?.getStringExtra(MainActivity.COMMAND)){ when(intent?.getStringExtra(MainActivity.COMMAND)){
MainActivity.STOP ->{ MainActivity.STOP ->{
val pi: PendingIntent? = intent.getParcelableExtra(MainActivity.PARAM_PINTENT)
stopVpn(pi) stopVpn(pi)
startForeground(FOREGROUND_ID, foregroundNotification("Yggdrasil service stopped")) startForeground(FOREGROUND_ID, foregroundNotification("Yggdrasil service stopped"))
} }
@ -67,7 +70,6 @@ class YggdrasilTunService : VpnService() {
val peers = deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.PEERS)) val peers = deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.PEERS))
val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS)) val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS))
val staticIP: Boolean = intent.getBooleanExtra(MainActivity.STATIC_IP, false) val staticIP: Boolean = intent.getBooleanExtra(MainActivity.STATIC_IP, false)
val pi: PendingIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT)
ygg = Yggdrasil() ygg = Yggdrasil()
setupTunInterface(pi, peers, dns, staticIP) setupTunInterface(pi, peers, dns, staticIP)
startForeground(FOREGROUND_ID, foregroundNotification("Yggdrasil service started")) startForeground(FOREGROUND_ID, foregroundNotification("Yggdrasil service started"))
@ -76,6 +78,9 @@ class YggdrasilTunService : VpnService() {
val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS)) val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS))
setupIOStreams(dns) setupIOStreams(dns)
} }
MainActivity.UPDATE_PEERS ->{
sendMeshPeerStatus(pi)
}
} }
return START_NOT_STICKY return START_NOT_STICKY
@ -141,11 +146,22 @@ class YggdrasilTunService : VpnService() {
writePacketsToTun(yggConduitEndpoint) writePacketsToTun(yggConduitEndpoint)
} }
} }
val intent: Intent = Intent().putExtra(MainActivity.IPv6, address) val intent: Intent = Intent().putExtra(MainActivity.IPv6, address)
pi.send(this, MainActivity.STATUS_FINISH, intent) pi.send(this, MainActivity.STATUS_FINISH, intent)
} }
private fun sendMeshPeerStatus(pi: PendingIntent?){
class Token : TypeToken<List<Peer>>()
var add = ygg.addressString
var meshPeers: List<Peer> = gson.fromJson(ygg.peersJSON, Token().type)
val intent: Intent = Intent().putStringArrayListExtra(
MainActivity.MESH_PEERS,
convertPeer2PeerStringList(meshPeers)
);
pi?.send(this, MainActivity.STATUS_PEERS_UPDATE, intent)
}
private fun fixConfig( private fun fixConfig(
config: MutableMap<Any?, Any?>, config: MutableMap<Any?, Any?>,
peers: Set<PeerInfo>, peers: Set<PeerInfo>,
@ -231,7 +247,6 @@ class YggdrasilTunService : VpnService() {
private fun stopVpn(pi: PendingIntent?) { private fun stopVpn(pi: PendingIntent?) {
isClosed = true; isClosed = true;
tunInputStream!!.close() tunInputStream!!.close()
tunOutputStream!!.close() tunOutputStream!!.close()
tunInterface!!.close() tunInterface!!.close()

View File

@ -19,12 +19,28 @@ class PeerInfo {
this.port = port this.port = port
this.countryCode = countryCode this.countryCode = countryCode
} }
constructor(schema: String, address: InetAddress, port: Int, countryCode: String?, isMeshPeer: Boolean){
this.schema = schema
this.address = address
var a = address.toString();
if(a.lastIndexOf('/')>0){
this.hostName = a.split("/")[0]
} else {
this.hostName = a.substring(1)
}
this.port = port
this.countryCode = countryCode
this.isMeshPeer = isMeshPeer
}
var schema: String var schema: String
var address: InetAddress var address: InetAddress
var hostName: String var hostName: String
var port = 0 var port = 0
var countryCode: String var countryCode: String?=null
var ping: Int = Int.MAX_VALUE var ping: Int = Int.MAX_VALUE
var isMeshPeer = false
override fun toString(): String { override fun toString(): String {
if(this.hostName.contains(":")) { if(this.hostName.contains(":")) {
@ -39,7 +55,14 @@ class PeerInfo {
} }
fun getCountry(context: Context): CCPCountry? { fun getCountry(context: Context): CCPCountry? {
return CCPCountry.getCountryForNameCodeFromLibraryMasterList(context, CountryCodePicker.Language.ENGLISH, countryCode) if(countryCode==null){
return null
} else {
return CCPCountry.getCountryForNameCodeFromLibraryMasterList(
context,
CountryCodePicker.Language.ENGLISH,
countryCode
)
}
} }
} }

View File

@ -0,0 +1,13 @@
package io.github.chronosx88.yggdrasil.models.config
import com.google.gson.annotations.SerializedName
data class Peer (
//Example [{"PublicKey":[154,201,118,156,19,74,134,115,94,159,76,86,36,192,221,105,220,254,226,161,108,226,17,192,75,243,225,15,42,195,155,2],"Endpoint":"(self)","BytesSent":0,"BytesRecvd":0,"Protocol":"self","Port":0,"Uptime":209900460}]
@SerializedName("Endpoint") var endpoint : String,
@SerializedName("Port") var port : Int,
@SerializedName("Uptime") var uptime : Long,
@SerializedName("Protocol") var protocol : String,
@SerializedName("BytesSent") var bytesSent : Long,
@SerializedName("BytesRecvd") var bytesReceived : Long
)

View File

@ -31,7 +31,11 @@ class PeerInfoListAdapter(
peerInfoHolder = listItem.tag as PeerInfoHolder peerInfoHolder = listItem.tag as PeerInfoHolder
} }
val currentPeer = allPeers[position] val currentPeer = allPeers[position]
peerInfoHolder.countryFlag.setImageResource(currentPeer.getCountry(mContext)!!.flagID) if(currentPeer.isMeshPeer){
//TODO set mesh icon
} else {
peerInfoHolder.countryFlag.setImageResource(currentPeer.getCountry(mContext)!!.flagID)
}
peerInfoHolder.peerInfoText.text = currentPeer.toString() peerInfoHolder.peerInfoText.text = currentPeer.toString()
return listItem!! return listItem!!
} }

View File

@ -99,5 +99,39 @@ class Utils {
return out return out
} }
@JvmStatic
fun convertPeer2PeerStringList(list: List<Peer>): ArrayList<String> {
var out = ArrayList<String>()
var gson = Gson()
for(p in list) {
out.add(gson.toJson(p))
}
return out
}
@JvmStatic
fun deserializePeerStringList2PeerInfoSet(list: List<String>?): MutableSet<PeerInfo> {
var gson = Gson()
var out = mutableSetOf<PeerInfo>()
if (list != null) {
for(s in list) {
var p = gson.fromJson(s, Peer::class.java)
if(p.endpoint == "(self)"){
out.add(PeerInfo(p.protocol, InetAddress.getByName("localhost"), p.port, null, true))
} else {
out.add(
PeerInfo(
p.protocol,
InetAddress.getByName(p.endpoint),
p.port,
null,
true
)
)
}
}
}
return out
}
} }
} }