mirror of
https://github.com/yggdrasil-network/crispa-android.git
synced 2024-11-09 20:11:01 +00:00
Merge pull request #21 from vikulin/master
Added Android 4 support (API 15)
This commit is contained in:
commit
addb9ac8a6
@ -6,10 +6,10 @@ android {
|
|||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "io.github.chronosx88.yggdrasil"
|
applicationId "io.github.chronosx88.yggdrasil"
|
||||||
minSdkVersion 21
|
minSdkVersion 15
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 3
|
versionCode 4
|
||||||
versionName "1.3"
|
versionName "1.4"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
project.ext.set("archivesBaseName", project.getParent().name+"-"+versionName)
|
project.ext.set("archivesBaseName", project.getParent().name+"-"+versionName)
|
||||||
}
|
}
|
||||||
@ -36,6 +36,12 @@ android {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = '1.8'
|
||||||
}
|
}
|
||||||
|
lintOptions {
|
||||||
|
checkReleaseBuilds false
|
||||||
|
// Or, if you prefer, you can continue to check for errors in release builds,
|
||||||
|
// but continue the build even when errors are found:
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task ndkBuild(type: Exec) {
|
task ndkBuild(type: Exec) {
|
||||||
@ -48,7 +54,6 @@ gradle.projectsEvaluated {
|
|||||||
tasks.compileDebugKotlin.dependsOn(ndkBuild)
|
tasks.compileDebugKotlin.dependsOn(ndkBuild)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation project(path: ':yggdrasil')
|
implementation project(path: ':yggdrasil')
|
||||||
@ -59,7 +64,7 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
|
||||||
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
implementation 'com.hbb20:ccp:2.4.0'
|
implementation 'com.hbb20:ccp:2.4.0'
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ class DNSListActivity : AppCompatActivity() {
|
|||||||
var ccpInput = view.findViewById<com.hbb20.CountryCodePicker>(R.id.ccp)
|
var ccpInput = view.findViewById<com.hbb20.CountryCodePicker>(R.id.ccp)
|
||||||
var ip = ipInput.text.toString().toLowerCase()
|
var ip = ipInput.text.toString().toLowerCase()
|
||||||
var ccp = ccpInput.selectedCountryNameCode
|
var ccp = ccpInput.selectedCountryNameCode
|
||||||
GlobalScope.launch {
|
thread(start = true) {
|
||||||
var di = DNSInfo(InetAddress.getByName("["+ip+"]"), ccp, "User DNS")
|
var di = DNSInfo(InetAddress.getByName("["+ip+"]"), ccp, "User DNS")
|
||||||
try {
|
try {
|
||||||
var ping = ping(di.address, 53)
|
var ping = ping(di.address, 53)
|
||||||
@ -115,8 +115,8 @@ class DNSListActivity : AppCompatActivity() {
|
|||||||
} catch(e: Throwable){
|
} catch(e: Throwable){
|
||||||
di.ping = Int.MAX_VALUE
|
di.ping = Int.MAX_VALUE
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
runOnUiThread {
|
||||||
var selectAdapter = (findViewById<ListView>(R.id.peerList).adapter as SelectDNSInfoListAdapter)
|
var selectAdapter = (findViewById<ListView>(R.id.dnsList).adapter as SelectDNSInfoListAdapter)
|
||||||
selectAdapter.addItem(0, di)
|
selectAdapter.addItem(0, di)
|
||||||
selectAdapter.notifyDataSetChanged()
|
selectAdapter.notifyDataSetChanged()
|
||||||
ad.dismiss()
|
ad.dismiss()
|
||||||
|
@ -3,7 +3,10 @@ package io.github.chronosx88.yggdrasil
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.content.*
|
import android.content.*
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
import android.net.VpnService
|
import android.net.VpnService
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
@ -11,9 +14,11 @@ import android.view.View
|
|||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import dalvik.system.DexFile
|
||||||
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.DNSInfoListAdapter
|
import io.github.chronosx88.yggdrasil.models.config.DNSInfoListAdapter
|
||||||
|
import io.github.chronosx88.yggdrasil.models.config.NetworkUtils
|
||||||
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.deserializePeerStringList2PeerInfoSet
|
||||||
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet
|
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet
|
||||||
@ -22,11 +27,6 @@ import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeS
|
|||||||
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
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
@ -62,12 +62,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
@JvmStatic var isStarted = false
|
@JvmStatic var isStarted = false
|
||||||
@JvmStatic var isCancelled = false
|
@JvmStatic var isCancelled = false
|
||||||
@JvmStatic var address = ""
|
@JvmStatic var address:String? = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
private var networkStateReceiver: BroadcastReceiver? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -143,11 +143,60 @@ class MainActivity : AppCompatActivity() {
|
|||||||
ipLayout.visibility = View.VISIBLE
|
ipLayout.visibility = View.VISIBLE
|
||||||
findViewById<TextView>(R.id.ip).text = address
|
findViewById<TextView>(R.id.ip).text = address
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
connectivityManager?.let {
|
||||||
|
it.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
|
||||||
|
override fun onAvailable(network: Network) {
|
||||||
|
if(isStarted) {
|
||||||
|
stopVpn()
|
||||||
|
Thread.sleep(1000)
|
||||||
|
startVpn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onLost(network: Network?) {
|
||||||
|
if(isStarted) {
|
||||||
|
stopVpn()
|
||||||
|
Thread.sleep(1000)
|
||||||
|
startVpn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
networkStateReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
val status: Int = NetworkUtils.getConnectivityStatusString(context)
|
||||||
|
Log.i(TAG, "Network state has been changed")
|
||||||
|
if ("android.net.conn.CONNECTIVITY_CHANGE" == intent.action) {
|
||||||
|
if (status == NetworkUtils.NETWORK_STATUS_NOT_CONNECTED) {
|
||||||
|
if(isStarted) {
|
||||||
|
stopVpn()
|
||||||
|
Thread.sleep(1000)
|
||||||
|
startVpn()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(isStarted) {
|
||||||
|
stopVpn()
|
||||||
|
Thread.sleep(1000)
|
||||||
|
startVpn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
val sourceDir: String = this.applicationInfo.sourceDir
|
||||||
|
val dexFile = DexFile(sourceDir)
|
||||||
|
val cl = classLoader
|
||||||
|
val c: Class<*> = dexFile.loadClass("dummy/Dummy", cl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stopVpn(){
|
private fun stopVpn(){
|
||||||
Log.d(TAG,"Stop")
|
Log.i(TAG,"Stop")
|
||||||
val intent = Intent(this, YggdrasilTunService::class.java)
|
val intent = Intent(this, YggdrasilTunService::class.java)
|
||||||
val TASK_CODE = 100
|
val TASK_CODE = 100
|
||||||
val pi = createPendingResult(TASK_CODE, intent, 0)
|
val pi = createPendingResult(TASK_CODE, intent, 0)
|
||||||
@ -157,7 +206,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startVpn(){
|
private fun startVpn(){
|
||||||
Log.d(TAG,"Start")
|
Log.i(TAG,"Start")
|
||||||
val intent= VpnService.prepare(this)
|
val intent= VpnService.prepare(this)
|
||||||
if (intent!=null){
|
if (intent!=null){
|
||||||
startActivityForResult(intent, VPN_REQUEST_CODE)
|
startActivityForResult(intent, VPN_REQUEST_CODE)
|
||||||
@ -167,7 +216,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDNS(){
|
private fun updateDNS(){
|
||||||
Log.d(TAG,"Update DNS")
|
Log.i(TAG,"Update DNS")
|
||||||
val intent = Intent(this, YggdrasilTunService::class.java)
|
val intent = Intent(this, YggdrasilTunService::class.java)
|
||||||
val TASK_CODE = 100
|
val TASK_CODE = 100
|
||||||
val pi = createPendingResult(TASK_CODE, intent, 0)
|
val pi = createPendingResult(TASK_CODE, intent, 0)
|
||||||
@ -230,7 +279,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
//save to shared preferences
|
//save to shared preferences
|
||||||
val preferences =
|
val preferences =
|
||||||
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
||||||
preferences.edit().putStringSet(CURRENT_PEERS, HashSet(currentPeers)).apply()
|
preferences.edit().putStringSet(CURRENT_PEERS, currentPeers!!.toHashSet()).apply()
|
||||||
if(isStarted){
|
if(isStarted){
|
||||||
//TODO implement UpdateConfig method in native interface and apply peer changes
|
//TODO implement UpdateConfig method in native interface and apply peer changes
|
||||||
stopVpn()
|
stopVpn()
|
||||||
@ -254,7 +303,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
//save to shared preferences
|
//save to shared preferences
|
||||||
val preferences =
|
val preferences =
|
||||||
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
||||||
preferences.edit().putStringSet(CURRENT_DNS, HashSet(currentDNS)).apply()
|
preferences.edit().putStringSet(CURRENT_DNS, currentDNS!!.toHashSet()).apply()
|
||||||
if(isStarted){
|
if(isStarted){
|
||||||
updateDNS()
|
updateDNS()
|
||||||
}
|
}
|
||||||
@ -332,8 +381,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
if (meshPeersReceiver != null){
|
if (networkStateReceiver != null){
|
||||||
unregisterReceiver(meshPeersReceiver);
|
unregisterReceiver(networkStateReceiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package io.github.chronosx88.yggdrasil
|
package io.github.chronosx88.yggdrasil
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -140,7 +139,9 @@ class PeerListActivity : AppCompatActivity() {
|
|||||||
var schemaInput = view.findViewById<TextView>(R.id.schemaInput)
|
var schemaInput = view.findViewById<TextView>(R.id.schemaInput)
|
||||||
var ipInput = view.findViewById<TextView>(R.id.ipInput)
|
var ipInput = view.findViewById<TextView>(R.id.ipInput)
|
||||||
ipInput.requestFocus()
|
ipInput.requestFocus()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
schemaInput.showSoftInputOnFocus = false
|
schemaInput.showSoftInputOnFocus = false
|
||||||
|
}
|
||||||
schemaInput.setOnFocusChangeListener { v, _ ->
|
schemaInput.setOnFocusChangeListener { v, _ ->
|
||||||
if(schemaInput.isFocused) {
|
if(schemaInput.isFocused) {
|
||||||
onClickSchemaList(v)
|
onClickSchemaList(v)
|
||||||
@ -159,8 +160,20 @@ class PeerListActivity : AppCompatActivity() {
|
|||||||
var portInput = view.findViewById<TextView>(R.id.portInput)
|
var portInput = view.findViewById<TextView>(R.id.portInput)
|
||||||
var ccpInput = view.findViewById<com.hbb20.CountryCodePicker>(R.id.ccp)
|
var ccpInput = view.findViewById<com.hbb20.CountryCodePicker>(R.id.ccp)
|
||||||
var schema = schemaInput.text.toString().toLowerCase()
|
var schema = schemaInput.text.toString().toLowerCase()
|
||||||
|
if(schema.isEmpty()){
|
||||||
|
schemaInput.error = "Schema is required"
|
||||||
|
}
|
||||||
var ip = ipInput.text.toString().toLowerCase()
|
var ip = ipInput.text.toString().toLowerCase()
|
||||||
|
if(ip.isEmpty()){
|
||||||
|
ipInput.error = "IP address is required"
|
||||||
|
}
|
||||||
var port = portInput.text.toString().toInt()
|
var port = portInput.text.toString().toInt()
|
||||||
|
if(port<=0){
|
||||||
|
portInput.error = "Port should be > 0"
|
||||||
|
}
|
||||||
|
if(port>=Short.MAX_VALUE){
|
||||||
|
portInput.error = "Port should be < "+Short.MAX_VALUE
|
||||||
|
}
|
||||||
var ccp = ccpInput.selectedCountryNameCode
|
var ccp = ccpInput.selectedCountryNameCode
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
var pi = PeerInfo(schema, InetAddress.getByName(ip), port, ccp)
|
var pi = PeerInfo(schema, InetAddress.getByName(ip), port, ccp)
|
||||||
|
@ -31,35 +31,29 @@ import java.net.Inet6Address
|
|||||||
class YggdrasilTunService : VpnService() {
|
class YggdrasilTunService : VpnService() {
|
||||||
|
|
||||||
private lateinit var ygg: Yggdrasil
|
private lateinit var ygg: Yggdrasil
|
||||||
|
private lateinit var tunInputStream: InputStream
|
||||||
|
private lateinit var tunOutputStream: OutputStream
|
||||||
|
private lateinit var address: String
|
||||||
private var isClosed = false
|
private var isClosed = false
|
||||||
|
|
||||||
/** Maximum packet size is constrained by the MTU, which is given as a signed short/2 */
|
/** Maximum packet size is constrained by the MTU, which is given as a signed short/2 */
|
||||||
private val MAX_PACKET_SIZE = Short.MAX_VALUE/2
|
private val MAX_PACKET_SIZE = Short.MAX_VALUE/2
|
||||||
|
private var tunInterface: ParcelFileDescriptor? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "Yggdrasil-service"
|
private const val TAG = "Yggdrasil-service"
|
||||||
}
|
}
|
||||||
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
|
|
||||||
|
|
||||||
private var mNotificationManager: NotificationManager? = null
|
private var scope: CoroutineScope? = null
|
||||||
|
|
||||||
private val FOREGROUND_ID = 1338
|
private val FOREGROUND_ID = 1338
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
val pi: PendingIntent? = intent?.getParcelableExtra(MainActivity.PARAM_PINTENT)
|
||||||
when(intent?.getStringExtra(MainActivity.COMMAND)){
|
when(intent?.getStringExtra(MainActivity.COMMAND)){
|
||||||
MainActivity.STOP ->{
|
MainActivity.STOP ->{
|
||||||
stopVpn(pi)
|
stopVpn(pi)
|
||||||
startForeground(FOREGROUND_ID, foregroundNotification("Yggdrasil service stopped"))
|
foregroundNotification(FOREGROUND_ID, "Yggdrasil service stopped")
|
||||||
}
|
}
|
||||||
MainActivity.START ->{
|
MainActivity.START ->{
|
||||||
val peers = deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.CURRENT_PEERS))
|
val peers = deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.CURRENT_PEERS))
|
||||||
@ -67,7 +61,7 @@ class YggdrasilTunService : VpnService() {
|
|||||||
val staticIP: Boolean = intent.getBooleanExtra(MainActivity.STATIC_IP, false)
|
val staticIP: Boolean = intent.getBooleanExtra(MainActivity.STATIC_IP, false)
|
||||||
ygg = Yggdrasil()
|
ygg = Yggdrasil()
|
||||||
setupTunInterface(pi, peers, dns, staticIP)
|
setupTunInterface(pi, peers, dns, staticIP)
|
||||||
startForeground(FOREGROUND_ID, foregroundNotification("Yggdrasil service started"))
|
foregroundNotification(FOREGROUND_ID, "Yggdrasil service started")
|
||||||
}
|
}
|
||||||
MainActivity.UPDATE_DNS ->{
|
MainActivity.UPDATE_DNS ->{
|
||||||
val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.CURRENT_DNS))
|
val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.CURRENT_DNS))
|
||||||
@ -84,11 +78,18 @@ class YggdrasilTunService : VpnService() {
|
|||||||
private fun setupIOStreams(dns: MutableSet<DNSInfo>){
|
private fun setupIOStreams(dns: MutableSet<DNSInfo>){
|
||||||
address = ygg.addressString
|
address = ygg.addressString
|
||||||
|
|
||||||
var builder = Builder()
|
var builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
.addAddress(address!!, 7)
|
Builder()
|
||||||
|
.addAddress(address, 7)
|
||||||
.allowFamily(OsConstants.AF_INET)
|
.allowFamily(OsConstants.AF_INET)
|
||||||
.allowBypass()
|
.allowBypass()
|
||||||
|
.setBlocking(true)
|
||||||
.setMtu(MAX_PACKET_SIZE)
|
.setMtu(MAX_PACKET_SIZE)
|
||||||
|
} else {
|
||||||
|
Builder()
|
||||||
|
.addAddress(address, 7)
|
||||||
|
.setMtu(MAX_PACKET_SIZE)
|
||||||
|
}
|
||||||
if (dns.size > 0) {
|
if (dns.size > 0) {
|
||||||
for (d in dns) {
|
for (d in dns) {
|
||||||
builder.addDnsServer(d.address)
|
builder.addDnsServer(d.address)
|
||||||
@ -100,15 +101,9 @@ class YggdrasilTunService : VpnService() {
|
|||||||
if(!hasIpv6DefaultRoute()){
|
if(!hasIpv6DefaultRoute()){
|
||||||
builder.addRoute("2000::",3)
|
builder.addRoute("2000::",3)
|
||||||
}
|
}
|
||||||
if(tunInterface!=null){
|
|
||||||
tunInterface!!.close()
|
|
||||||
tunInputStream!!.close()
|
|
||||||
tunOutputStream!!.close()
|
|
||||||
}
|
|
||||||
tunInterface = builder.establish()
|
tunInterface = builder.establish()
|
||||||
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
|
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
|
||||||
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
|
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupTunInterface(
|
private fun setupTunInterface(
|
||||||
@ -132,7 +127,7 @@ class YggdrasilTunService : VpnService() {
|
|||||||
val job = SupervisorJob()
|
val job = SupervisorJob()
|
||||||
scope = CoroutineScope(Dispatchers.Default + job)
|
scope = CoroutineScope(Dispatchers.Default + job)
|
||||||
scope!!.launch {
|
scope!!.launch {
|
||||||
val buffer = ByteArray(2048)
|
val buffer = ByteArray(MAX_PACKET_SIZE)
|
||||||
while (!isClosed) {
|
while (!isClosed) {
|
||||||
readPacketsFromTun(yggConduitEndpoint, buffer)
|
readPacketsFromTun(yggConduitEndpoint, buffer)
|
||||||
}
|
}
|
||||||
@ -148,7 +143,7 @@ class YggdrasilTunService : VpnService() {
|
|||||||
|
|
||||||
private fun sendMeshPeerStatus(pi: PendingIntent?){
|
private fun sendMeshPeerStatus(pi: PendingIntent?){
|
||||||
class Token : TypeToken<List<Peer>>()
|
class Token : TypeToken<List<Peer>>()
|
||||||
var add = ygg.addressString
|
ygg.addressString
|
||||||
var meshPeers: List<Peer> = gson.fromJson(ygg.peersJSON, Token().type)
|
var meshPeers: List<Peer> = gson.fromJson(ygg.peersJSON, Token().type)
|
||||||
val intent: Intent = Intent().putStringArrayListExtra(
|
val intent: Intent = Intent().putStringArrayListExtra(
|
||||||
MainActivity.MESH_PEERS,
|
MainActivity.MESH_PEERS,
|
||||||
@ -219,12 +214,8 @@ class YggdrasilTunService : VpnService() {
|
|||||||
private fun readPacketsFromTun(yggConduitEndpoint: ConduitEndpoint, buffer: ByteArray) {
|
private fun readPacketsFromTun(yggConduitEndpoint: ConduitEndpoint, buffer: ByteArray) {
|
||||||
try {
|
try {
|
||||||
// Read the outgoing packet from the input stream.
|
// Read the outgoing packet from the input stream.
|
||||||
val length = tunInputStream?.read(buffer) ?: 1
|
val length = tunInputStream.read(buffer)
|
||||||
if (length > 0){
|
|
||||||
yggConduitEndpoint.send(buffer.sliceArray(IntRange(0, length - 1)))
|
yggConduitEndpoint.send(buffer.sliceArray(IntRange(0, length - 1)))
|
||||||
} else {
|
|
||||||
Thread.sleep(100)
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@ -234,7 +225,7 @@ class YggdrasilTunService : VpnService() {
|
|||||||
val buffer = yggConduitEndpoint.recv()
|
val buffer = yggConduitEndpoint.recv()
|
||||||
if(buffer!=null) {
|
if(buffer!=null) {
|
||||||
try {
|
try {
|
||||||
tunOutputStream?.write(buffer)
|
tunOutputStream.write(buffer)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@ -244,10 +235,9 @@ class YggdrasilTunService : VpnService() {
|
|||||||
private fun stopVpn(pi: PendingIntent?) {
|
private fun stopVpn(pi: PendingIntent?) {
|
||||||
isClosed = true;
|
isClosed = true;
|
||||||
scope!!.coroutineContext.cancelChildren()
|
scope!!.coroutineContext.cancelChildren()
|
||||||
tunInputStream!!.close()
|
tunInputStream.close()
|
||||||
tunOutputStream!!.close()
|
tunOutputStream.close()
|
||||||
tunInterface!!.close()
|
tunInterface!!.close()
|
||||||
tunInterface = null
|
|
||||||
Log.d(TAG,"Stop is running from service")
|
Log.d(TAG,"Stop is running from service")
|
||||||
ygg.stop()
|
ygg.stop()
|
||||||
val intent: Intent = Intent()
|
val intent: Intent = Intent()
|
||||||
@ -265,7 +255,9 @@ class YggdrasilTunService : VpnService() {
|
|||||||
private fun hasIpv6DefaultRoute(): Boolean {
|
private fun hasIpv6DefaultRoute(): Boolean {
|
||||||
val cm =
|
val cm =
|
||||||
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
val networks = cm.allNetworks
|
val networks = cm.allNetworks
|
||||||
|
|
||||||
for (network in networks) {
|
for (network in networks) {
|
||||||
val linkProperties = cm.getLinkProperties(network)
|
val linkProperties = cm.getLinkProperties(network)
|
||||||
if(linkProperties!=null) {
|
if(linkProperties!=null) {
|
||||||
@ -277,10 +269,12 @@ class YggdrasilTunService : VpnService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun foregroundNotification(text: String): Notification? {
|
private fun foregroundNotification(FOREGROUND_ID: Int, text: String) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
val channelId =
|
val channelId =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
createNotificationChannel(TAG, "Yggdrasil service")
|
createNotificationChannel(TAG, "Yggdrasil service")
|
||||||
@ -300,7 +294,8 @@ class YggdrasilTunService : VpnService() {
|
|||||||
.setContentText(text)
|
.setContentText(text)
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
.setTicker(text)
|
.setTicker(text)
|
||||||
return b.build()
|
startForeground(FOREGROUND_ID, b.build())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package io.github.chronosx88.yggdrasil.models.config
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkUtils {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val TYPE_WIFI = 1
|
||||||
|
val TYPE_MOBILE = 2
|
||||||
|
val TYPE_NOT_CONNECTED = 0
|
||||||
|
val NETWORK_STATUS_NOT_CONNECTED = 0
|
||||||
|
val NETWORK_STATUS_WIFI = 1
|
||||||
|
val NETWORK_STATUS_MOBILE = 2
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getConnectivityStatus(context: Context): Int {
|
||||||
|
val cm =
|
||||||
|
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
val activeNetwork = cm.activeNetworkInfo
|
||||||
|
if (null != activeNetwork) {
|
||||||
|
if (activeNetwork.type == ConnectivityManager.TYPE_WIFI) return TYPE_WIFI
|
||||||
|
if (activeNetwork.type == ConnectivityManager.TYPE_MOBILE) return TYPE_MOBILE
|
||||||
|
}
|
||||||
|
return TYPE_NOT_CONNECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getConnectivityStatusString(context: Context): Int {
|
||||||
|
val conn: Int = getConnectivityStatus(context)
|
||||||
|
var status = 0
|
||||||
|
if (conn == TYPE_WIFI) {
|
||||||
|
status = NETWORK_STATUS_WIFI
|
||||||
|
} else if (conn == TYPE_MOBILE) {
|
||||||
|
status = NETWORK_STATUS_MOBILE
|
||||||
|
} else if (conn == TYPE_NOT_CONNECTED) {
|
||||||
|
status = NETWORK_STATUS_NOT_CONNECTED
|
||||||
|
}
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,8 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
app:popupTheme="@style/AppTheme.PopupOverlay"
|
||||||
|
android:layout_marginRight="240dp" />
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/staticIP"
|
android:id="@+id/staticIP"
|
||||||
|
@ -22,5 +22,6 @@
|
|||||||
android:paddingEnd="20dp"
|
android:paddingEnd="20dp"
|
||||||
android:minHeight="22dp"
|
android:minHeight="22dp"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
android:textColor="@color/white"/>
|
android:textColor="@color/white"
|
||||||
|
android:paddingRight="20dp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -11,7 +11,8 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/hostInfoText"
|
app:layout_constraintStart_toEndOf="@+id/hostInfoText"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:layout_marginLeft="10dp" />
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/hostInfoText"
|
android:id="@+id/hostInfoText"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -24,7 +25,8 @@
|
|||||||
app:layout_constraintEnd_toStartOf="@+id/ping"
|
app:layout_constraintEnd_toStartOf="@+id/ping"
|
||||||
app:layout_constraintStart_toEndOf="@+id/countryFlag"
|
app:layout_constraintStart_toEndOf="@+id/countryFlag"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:layout_marginLeft="10dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/ping"
|
android:id="@+id/ping"
|
||||||
|
7
app/src/main/res/values-v21/styles.xml
Normal file
7
app/src/main/res/values-v21/styles.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="SwitchTheme" parent="Theme.AppCompat.Light">
|
||||||
|
<item name="android:colorControlActivated">@color/green</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -10,7 +10,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="SwitchTheme" parent="Theme.AppCompat.Light">
|
<style name="SwitchTheme" parent="Theme.AppCompat.Light">
|
||||||
<item name="android:colorControlActivated">@color/green</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="EditText.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
<style name="EditText.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
@ -4,6 +4,7 @@ buildscript {
|
|||||||
ext.kotlin_version = '1.3.72'
|
ext.kotlin_version = '1.3.72'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
mavenCentral()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
Loading…
Reference in New Issue
Block a user