diff options
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.kt | 34 |
1 files changed, 28 insertions, 6 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 40e9004..48cb1df 100644 --- a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt +++ b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon | 2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon |
3 | * Copyright (C) 2017-2019 Pacien TRAN-GIRARD | 3 | * Copyright (C) 2017-2020 Pacien TRAN-GIRARD |
4 | * | 4 | * |
5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -21,6 +21,7 @@ package org.pacien.tincapp.service | |||
21 | import android.app.Service | 21 | import android.app.Service |
22 | import android.content.Context | 22 | import android.content.Context |
23 | import android.content.Intent | 23 | import android.content.Intent |
24 | import android.net.LocalServerSocket | ||
24 | import android.net.VpnService | 25 | import android.net.VpnService |
25 | import android.os.ParcelFileDescriptor | 26 | import android.os.ParcelFileDescriptor |
26 | import androidx.localbroadcastmanager.content.LocalBroadcastManager | 27 | import androidx.localbroadcastmanager.content.LocalBroadcastManager |
@@ -43,6 +44,7 @@ import org.pacien.tincapp.intent.Actions | |||
43 | import org.pacien.tincapp.utils.TincKeyring | 44 | import org.pacien.tincapp.utils.TincKeyring |
44 | import org.slf4j.LoggerFactory | 45 | import org.slf4j.LoggerFactory |
45 | import java.io.FileNotFoundException | 46 | import java.io.FileNotFoundException |
47 | import java.security.AccessControlException | ||
46 | 48 | ||
47 | /** | 49 | /** |
48 | * @author pacien | 50 | * @author pacien |
@@ -100,6 +102,7 @@ class TincVpnService : VpnService() { | |||
100 | log.info("Starting tinc daemon for network \"$netName\".") | 102 | log.info("Starting tinc daemon for network \"$netName\".") |
101 | if (isConnected() || getCurrentNetName() != null) stopVpn().join() | 103 | if (isConnected() || getCurrentNetName() != null) stopVpn().join() |
102 | 104 | ||
105 | // FIXME: pass decrypted private keys via temp file | ||
103 | val privateKeys = try { | 106 | val privateKeys = try { |
104 | TincConfiguration.fromTincConfiguration(AppPaths.existing(AppPaths.tincConfFile(netName))).let { tincCfg -> | 107 | TincConfiguration.fromTincConfiguration(AppPaths.existing(AppPaths.tincConfFile(netName))).let { tincCfg -> |
105 | Pair( | 108 | Pair( |
@@ -125,13 +128,10 @@ class TincVpnService : VpnService() { | |||
125 | } | 128 | } |
126 | 129 | ||
127 | val deviceFd = try { | 130 | val deviceFd = try { |
128 | val appContextFd = Builder().setSession(netName) | 131 | Builder().setSession(netName) |
129 | .applyCfg(interfaceCfg) | 132 | .applyCfg(interfaceCfg) |
130 | .also { applyIgnoringException(it::addDisallowedApplication, BuildConfig.APPLICATION_ID) } | 133 | .also { applyIgnoringException(it::addDisallowedApplication, BuildConfig.APPLICATION_ID) } |
131 | .establish()!! | 134 | .establish()!! |
132 | val daemonContextFd = appContextFd.dup() // necessary since Android 10 | ||
133 | appContextFd.close() | ||
134 | daemonContextFd | ||
135 | } catch (e: IllegalArgumentException) { | 135 | } catch (e: IllegalArgumentException) { |
136 | return reportError(resources.getString(R.string.notification_error_message_network_config_invalid_format, e.defaultMessage()), e, "network-interface") | 136 | return reportError(resources.getString(R.string.notification_error_message_network_config_invalid_format, e.defaultMessage()), e, "network-interface") |
137 | } catch (e: NullPointerException) { | 137 | } catch (e: NullPointerException) { |
@@ -140,10 +140,15 @@ class TincVpnService : VpnService() { | |||
140 | return reportError(resources.getString(R.string.notification_error_message_could_not_configure_iface, e.defaultMessage()), e) | 140 | return reportError(resources.getString(R.string.notification_error_message_could_not_configure_iface, e.defaultMessage()), e) |
141 | } | 141 | } |
142 | 142 | ||
143 | val daemon = Tincd.start(netName, deviceFd.fd, privateKeys.first?.fd, privateKeys.second?.fd) | 143 | val serverSocket = LocalServerSocket(DEVICE_FD_ABSTRACT_SOCKET) |
144 | Executor.runAsyncTask { serveDeviceFd(serverSocket, deviceFd) } | ||
145 | |||
146 | // FIXME: pass decrypted private keys via temp file | ||
147 | val daemon = Tincd.start(netName, DEVICE_FD_ABSTRACT_SOCKET, null, null) | ||
144 | setState(netName, passphrase, interfaceCfg, deviceFd, daemon) | 148 | setState(netName, passphrase, interfaceCfg, deviceFd, daemon) |
145 | 149 | ||
146 | waitForDaemonStartup().whenComplete { _, exception -> | 150 | waitForDaemonStartup().whenComplete { _, exception -> |
151 | serverSocket.close() | ||
147 | deviceFd.close() | 152 | deviceFd.close() |
148 | privateKeys.first?.close() | 153 | privateKeys.first?.close() |
149 | privateKeys.second?.close() | 154 | privateKeys.second?.close() |
@@ -189,6 +194,22 @@ class TincVpnService : VpnService() { | |||
189 | LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(event)) | 194 | LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(event)) |
190 | } | 195 | } |
191 | 196 | ||
197 | private fun serveDeviceFd(serverSocket: LocalServerSocket, deviceFd: ParcelFileDescriptor) = | ||
198 | serverSocket.accept().let { socket -> | ||
199 | try { | ||
200 | if (socket.peerCredentials.uid != App.getApplicationInfo().uid) | ||
201 | throw AccessControlException("Peer UID mismatch.") | ||
202 | |||
203 | socket.setFileDescriptorsForSend(arrayOf(deviceFd.fileDescriptor)) | ||
204 | socket.outputStream.write(0) // dummy write | ||
205 | socket.outputStream.flush() | ||
206 | } catch (e: Exception) { | ||
207 | log.error("Error while serving device fd", e) | ||
208 | } finally { | ||
209 | socket.close() | ||
210 | } | ||
211 | } | ||
212 | |||
192 | private fun waitForDaemonStartup() = | 213 | private fun waitForDaemonStartup() = |
193 | Executor | 214 | Executor |
194 | .runAsyncTask { Thread.sleep(SETUP_DELAY) } | 215 | .runAsyncTask { Thread.sleep(SETUP_DELAY) } |
@@ -196,6 +217,7 @@ class TincVpnService : VpnService() { | |||
196 | 217 | ||
197 | companion object { | 218 | companion object { |
198 | private const val SETUP_DELAY = 500L // ms | 219 | private const val SETUP_DELAY = 500L // ms |
220 | private const val DEVICE_FD_ABSTRACT_SOCKET = "${BuildConfig.APPLICATION_ID}.daemon.socket" | ||
199 | 221 | ||
200 | private val STORE_NAME = this::class.java.`package`!!.name | 222 | private val STORE_NAME = this::class.java.`package`!!.name |
201 | private const val STORE_KEY_NETNAME = "netname" | 223 | private const val STORE_KEY_NETNAME = "netname" |