aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt')
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt105
1 files changed, 66 insertions, 39 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
index 12ac17f..cd1dd74 100644
--- a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
+++ b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
@@ -5,7 +5,10 @@ import android.content.Intent
5import android.net.Uri 5import android.net.Uri
6import android.net.VpnService 6import android.net.VpnService
7import android.os.ParcelFileDescriptor 7import android.os.ParcelFileDescriptor
8import android.util.Log
9import org.apache.commons.configuration2.ex.ConversionException
8import org.pacien.tincapp.BuildConfig 10import org.pacien.tincapp.BuildConfig
11import org.pacien.tincapp.R
9import org.pacien.tincapp.commands.Tinc 12import org.pacien.tincapp.commands.Tinc
10import org.pacien.tincapp.commands.Tincd 13import org.pacien.tincapp.commands.Tincd
11import org.pacien.tincapp.context.App 14import org.pacien.tincapp.context.App
@@ -13,9 +16,8 @@ import org.pacien.tincapp.context.AppPaths
13import org.pacien.tincapp.data.VpnInterfaceConfiguration 16import org.pacien.tincapp.data.VpnInterfaceConfiguration
14import org.pacien.tincapp.extensions.Java.applyIgnoringException 17import org.pacien.tincapp.extensions.Java.applyIgnoringException
15import org.pacien.tincapp.extensions.VpnServiceBuilder.applyCfg 18import org.pacien.tincapp.extensions.VpnServiceBuilder.applyCfg
16import org.pacien.tincapp.intent.action.ACTION_START_SERVICE
17import org.pacien.tincapp.intent.action.ACTION_STOP_SERVICE
18import org.pacien.tincapp.intent.action.TINC_SCHEME 19import org.pacien.tincapp.intent.action.TINC_SCHEME
20import java.io.FileNotFoundException
19import java.io.IOException 21import java.io.IOException
20 22
21/** 23/**
@@ -23,65 +25,90 @@ import java.io.IOException
23 */ 25 */
24class TincVpnService : VpnService() { 26class TincVpnService : VpnService() {
25 27
26 override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { 28 override fun onDestroy() {
27 when (intent.action) { 29 stopVpn()
28 ACTION_START_SERVICE -> startVpn(intent.data.schemeSpecificPart) 30 super.onDestroy()
29 ACTION_STOP_SERVICE -> onDestroy()
30 }
31
32 return Service.START_STICKY
33 } 31 }
34 32
35 override fun onDestroy() { 33 override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
36 connected = false 34 if (isConnected()) stopVpn()
37 35 startVpn(intent.data.schemeSpecificPart)
38 try { 36 return Service.START_REDELIVER_INTENT
39 if (netName != null) Tinc.stop(netName!!)
40 fd?.close()
41 } catch (e: IOException) {
42 e.printStackTrace()
43 } finally {
44 netName = null
45 interfaceCfg = null
46 fd = null
47 super.onDestroy()
48 }
49 } 37 }
50 38
51 private fun startVpn(netName: String) { 39 private fun startVpn(netName: String) {
52 if (isConnected()) onDestroy() 40 if (netName.isBlank())
53 TincVpnService.netName = netName 41 return reportError(resources.getString(R.string.message_no_network_name_provided), docTopic = "intent-api")
54 TincVpnService.interfaceCfg = VpnInterfaceConfiguration.fromIfaceConfiguration(AppPaths.netConfFile(netName)) 42
55 43 if (!AppPaths.confDir(netName).exists())
56 val net = Builder().setSession(netName).applyCfg(TincVpnService.interfaceCfg!!) 44 return reportError(resources.getString(R.string.message_no_configuration_for_network_format, netName), docTopic = "configuration")
57 applyIgnoringException(net::addDisallowedApplication, BuildConfig.APPLICATION_ID) 45
58 46 Log.i(TAG, "Starting tinc daemon for network \"$netName\".")
59 try { 47
60 fd = net.establish() 48 val interfaceCfg = try {
61 Tincd.start(netName, fd!!.fd) 49 VpnInterfaceConfiguration.fromIfaceConfiguration(AppPaths.existing(AppPaths.netConfFile(netName)))
62 } catch (e: IOException) { 50 } catch (e: FileNotFoundException) {
63 e.printStackTrace() 51 return reportError(resources.getString(R.string.message_network_config_not_found_format, e.message!!), e, "configuration")
52 } catch (e: ConversionException) {
53 return reportError(resources.getString(R.string.message_network_config_invalid_format, e.message!!), e, "network-interface")
64 } 54 }
65 55
66 connected = true 56 val fd = try {
57 Builder().setSession(netName)
58 .applyCfg(interfaceCfg)
59 .also { applyIgnoringException(it::addDisallowedApplication, BuildConfig.APPLICATION_ID) }
60 .establish()
61 } catch (e: IllegalArgumentException) {
62 return reportError(resources.getString(R.string.message_network_config_invalid_format, e.message!!), e, "network-interface")
63 }
64
65 Tincd.start(netName, fd!!.fd)
66 setState(true, netName, interfaceCfg, fd)
67 Log.i(TAG, "tinc daemon started.")
68 }
69
70 private fun reportError(msg: String, e: Throwable? = null, docTopic: String? = null) {
71 if (e != null)
72 Log.e(TAG, msg, e)
73 else
74 Log.e(TAG, msg)
75
76 App.alert(R.string.title_unable_to_start_tinc, msg,
77 if (docTopic != null) resources.getString(R.string.app_doc_url_format, docTopic) else null)
67 } 78 }
68 79
69 companion object { 80 companion object {
70 81
82 val TAG = this::class.java.canonicalName!!
83
71 private var connected: Boolean = false 84 private var connected: Boolean = false
72 private var netName: String? = null 85 private var netName: String? = null
73 private var interfaceCfg: VpnInterfaceConfiguration? = null 86 private var interfaceCfg: VpnInterfaceConfiguration? = null
74 private var fd: ParcelFileDescriptor? = null 87 private var fd: ParcelFileDescriptor? = null
75 88
89 private fun setState(connected: Boolean, netName: String?, interfaceCfg: VpnInterfaceConfiguration?, fd: ParcelFileDescriptor?) {
90 TincVpnService.connected = connected
91 TincVpnService.netName = netName
92 TincVpnService.interfaceCfg = interfaceCfg
93 TincVpnService.fd = fd
94 }
95
76 fun startVpn(netName: String) { 96 fun startVpn(netName: String) {
77 App.getContext().startService(Intent(App.getContext(), TincVpnService::class.java) 97 App.getContext().startService(Intent(App.getContext(), TincVpnService::class.java)
78 .setAction(ACTION_START_SERVICE)
79 .setData(Uri.Builder().scheme(TINC_SCHEME).opaquePart(netName).build())) 98 .setData(Uri.Builder().scheme(TINC_SCHEME).opaquePart(netName).build()))
80 } 99 }
81 100
82 fun stopVpn() { 101 fun stopVpn() {
83 App.getContext().startService(Intent(App.getContext(), TincVpnService::class.java) 102 try {
84 .setAction(ACTION_STOP_SERVICE)) 103 Log.i(TAG, "Stopping any running tinc daemon.")
104 if (netName != null) Tinc.stop(netName!!)
105 fd?.close()
106 Log.i(TAG, "All tinc daemons stopped.")
107 } catch (e: IOException) {
108 Log.wtf(TAG, e)
109 } finally {
110 setState(false, null, null, null)
111 }
85 } 112 }
86 113
87 fun getCurrentNetName() = netName 114 fun getCurrentNetName() = netName