summaryrefslogtreecommitdiffhomepage
path: root/android/src
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-05-29 11:50:07 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-05-29 11:50:07 -0300
commit6188daf9e1d3446084dcb2e11efd42806c79e0ab (patch)
tree58c4784ca316b8263f1596c475b8cc7f23e7d516 /android/src
parent0eb13af5be6a204f9c94783bd16498101bfbb97d (diff)
parentdcb94332ab4b9f881df1ba2fcf5d1ef449704fd4 (diff)
downloadmullvadvpn-6188daf9e1d3446084dcb2e11efd42806c79e0ab.tar.xz
mullvadvpn-6188daf9e1d3446084dcb2e11efd42806c79e0ab.zip
Merge branch 'vpn-service-tun-provider'
Diffstat (limited to 'android/src')
-rw-r--r--android/src/main/AndroidManifest.xml9
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt30
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt2
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt6
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt79
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/InetNetwork.kt5
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunConfig.kt10
7 files changed, 136 insertions, 5 deletions
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 450c316618..d025f278a5 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -22,5 +22,14 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <service
+ android:name=".MullvadVpnService$InnerVpnService"
+ android:permission="android.permission.BIND_VPN_SERVICE"
+ >
+ <intent-filter>
+ <action android:name="android.net.VpnService" />
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
index 4a853b2f7b..b288ecfdbc 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
@@ -7,7 +7,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
+import android.app.Activity
import android.content.Context
+import android.content.Intent
+import android.net.VpnService
import android.os.Bundle
import android.os.Handler
import android.support.v4.app.Fragment
@@ -24,7 +27,10 @@ class ConnectFragment : Fragment() {
private lateinit var notificationBanner: NotificationBanner
private lateinit var status: ConnectionStatus
+ private lateinit var parentActivity: MainActivity
+
private var daemon = CompletableDeferred<MullvadDaemon>()
+ private var vpnPermission = CompletableDeferred<Unit>()
private var generateWireguardKeyJob = generateWireguardKey()
@@ -36,7 +42,8 @@ class ConnectFragment : Fragment() {
override fun onAttach(context: Context) {
super.onAttach(context)
- waitForDaemonJob = waitForDaemon((context as MainActivity).asyncDaemon)
+ parentActivity = context as MainActivity
+ waitForDaemonJob = waitForDaemon(parentActivity.asyncDaemon)
}
override fun onCreateView(
@@ -75,6 +82,12 @@ class ConnectFragment : Fragment() {
super.onDestroyView()
}
+ override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
+ if (resultCode == Activity.RESULT_OK) {
+ vpnPermission.complete(Unit)
+ }
+ }
+
private fun waitForDaemon(asyncDaemon: Deferred<MullvadDaemon>) =
GlobalScope.launch(Dispatchers.Default) {
daemon.complete(asyncDaemon.await())
@@ -97,11 +110,26 @@ class ConnectFragment : Fragment() {
}
}
+ private fun requestVpnPermission() {
+ val intent = VpnService.prepare(parentActivity)
+
+ vpnPermission = CompletableDeferred<Unit>()
+
+ if (intent != null) {
+ startActivityForResult(intent, 0)
+ } else {
+ onActivityResult(0, Activity.RESULT_OK, null)
+ }
+ }
+
private fun connect() {
updateViewToPreConnecting()
activeAction?.cancel()
+ requestVpnPermission()
+
activeAction = GlobalScope.launch(Dispatchers.Default) {
+ vpnPermission.await()
generateWireguardKeyJob.join()
daemon.await().connect()
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
index 6e3d34730b..320b2e1c94 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
@@ -68,7 +68,7 @@ class MainActivity : FragmentActivity() {
private fun startDaemon() = GlobalScope.async(Dispatchers.Default) {
activityCreated.await()
ApiRootCaFile().extract(this@MainActivity)
- MullvadDaemon()
+ MullvadDaemon(MullvadVpnService(this@MainActivity))
}
private fun fetchRelayList() = GlobalScope.async(Dispatchers.Default) {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
index e9f54769b2..ff3abeea80 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
@@ -7,10 +7,10 @@ import net.mullvad.mullvadvpn.model.RelaySettingsUpdate
import net.mullvad.mullvadvpn.model.Settings
import net.mullvad.mullvadvpn.model.TunnelStateTransition
-class MullvadDaemon {
+class MullvadDaemon(val vpnService: MullvadVpnService) {
init {
System.loadLibrary("mullvad_jni")
- initialize()
+ initialize(vpnService)
}
var onTunnelStateChange: ((TunnelStateTransition) -> Unit)? = null
@@ -25,7 +25,7 @@ class MullvadDaemon {
external fun setAccount(accountToken: String?)
external fun updateRelaySettings(update: RelaySettingsUpdate)
- private external fun initialize()
+ private external fun initialize(vpnService: MullvadVpnService)
private fun notifyTunnelStateEvent(event: TunnelStateTransition) {
onTunnelStateChange?.invoke(event)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt
new file mode 100644
index 0000000000..dcd4935ee4
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt
@@ -0,0 +1,79 @@
+package net.mullvad.mullvadvpn
+
+import java.net.InetAddress
+
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.CompletableDeferred
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.net.VpnService
+
+import net.mullvad.mullvadvpn.model.TunConfig
+
+var INNER_VPN_SERVICE = CompletableDeferred<MullvadVpnService.InnerVpnService>()
+var SERVICE_NOT_RUNNING = true
+
+class MullvadVpnService(val context: Context) {
+ class InnerVpnService : VpnService() {
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ INNER_VPN_SERVICE.complete(this)
+
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ override fun onDestroy() {
+ INNER_VPN_SERVICE = CompletableDeferred<MullvadVpnService.InnerVpnService>()
+ SERVICE_NOT_RUNNING = true
+ super.onDestroy()
+ }
+
+ fun builder(): Builder {
+ return Builder()
+ }
+ }
+
+ fun createTun(config: TunConfig): Int {
+ return createTun(config, startService())
+ }
+
+ fun bypass(socket: Int): Boolean {
+ return startService().protect(socket)
+ }
+
+ private fun startService(): InnerVpnService {
+ lateinit var service: InnerVpnService
+
+ if (SERVICE_NOT_RUNNING) {
+ SERVICE_NOT_RUNNING = false
+ context.startService(Intent(context, InnerVpnService::class.java))
+ }
+
+ runBlocking { service = INNER_VPN_SERVICE.await() }
+
+ return service
+ }
+
+ private fun createTun(config: TunConfig, service: InnerVpnService): Int {
+ val builder = service.builder().apply {
+ for (address in config.addresses) {
+ addAddress(address, 32)
+ }
+
+ for (dnsServer in config.dnsServers) {
+ addDnsServer(dnsServer)
+ }
+
+ for (route in config.routes) {
+ addRoute(route.address, route.prefixLength as Int)
+ }
+
+ setMtu(config.mtu)
+ }
+
+ val vpnInterface = builder.establish()
+
+ return vpnInterface.detachFd()
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/InetNetwork.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/InetNetwork.kt
new file mode 100644
index 0000000000..eb3030880f
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/InetNetwork.kt
@@ -0,0 +1,5 @@
+package net.mullvad.mullvadvpn.model
+
+import java.net.InetAddress
+
+data class InetNetwork(val address: InetAddress, val prefixLength: Short)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunConfig.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunConfig.kt
new file mode 100644
index 0000000000..929e03b99a
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunConfig.kt
@@ -0,0 +1,10 @@
+package net.mullvad.mullvadvpn.model
+
+import java.net.InetAddress
+
+data class TunConfig(
+ val addresses: List<InetAddress>,
+ val dnsServers: List<InetAddress>,
+ val routes: List<InetNetwork>,
+ val mtu: Int
+)