diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-29 11:50:07 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-29 11:50:07 -0300 |
| commit | 6188daf9e1d3446084dcb2e11efd42806c79e0ab (patch) | |
| tree | 58c4784ca316b8263f1596c475b8cc7f23e7d516 /android/src | |
| parent | 0eb13af5be6a204f9c94783bd16498101bfbb97d (diff) | |
| parent | dcb94332ab4b9f881df1ba2fcf5d1ef449704fd4 (diff) | |
| download | mullvadvpn-6188daf9e1d3446084dcb2e11efd42806c79e0ab.tar.xz mullvadvpn-6188daf9e1d3446084dcb2e11efd42806c79e0ab.zip | |
Merge branch 'vpn-service-tun-provider'
Diffstat (limited to 'android/src')
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 +) |
