Temporary Wi-Fi hotspot for bypassing tethering limits (#18)

* First draft of temporary hotspot
* Refactor with LocalOnlyInterfaceManager
* Refactor LocalOnlyHotspotService
* Localize
* Update strict summary
This commit is contained in:
Mygod
2018-05-02 17:53:06 -07:00
committed by GitHub
parent 0a47cfdf1c
commit 2fe7703d6d
15 changed files with 420 additions and 185 deletions

View File

@@ -1,16 +1,18 @@
package be.mygod.vpnhotspot
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.support.v4.content.LocalBroadcastManager
import android.widget.Toast
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.*
import be.mygod.vpnhotspot.net.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.Routing
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.VpnMonitor
import java.net.InetAddress
import java.net.SocketException
class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Callback {
class TetheringService : IpNeighbourMonitoringService(), VpnMonitor.Callback {
companion object {
const val EXTRA_ADD_INTERFACE = "interface.add"
const val EXTRA_REMOVE_INTERFACE = "interface.remove"
@@ -24,7 +26,6 @@ class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Call
private val binder = TetheringBinder()
private val routings = HashMap<String, Routing?>()
private var neighbours = emptyList<IpNeighbour>()
private var upstream: String? = null
private var dns: List<InetAddress> = emptyList()
private var receiverRegistered = false
@@ -32,9 +33,8 @@ class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Call
synchronized(routings) {
when (intent.action) {
TetheringManager.ACTION_TETHER_STATE_CHANGED -> {
val remove = routings.keys - TetheringManager.getTetheredIfaces(intent.extras)
if (remove.isEmpty()) return@broadcastReceiver
val failed = remove.any { routings.remove(it)?.stop() == false }
val failed = (routings.keys - TetheringManager.getTetheredIfaces(intent.extras))
.any { routings.remove(it)?.stop() == false }
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
}
App.ACTION_CLEAN_ROUTINGS -> for (iface in routings.keys) routings[iface] = null
@@ -42,13 +42,10 @@ class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Call
updateRoutingsLocked()
}
}
override val activeIfaces get() = synchronized(routings) { routings.keys.toList() }
private fun updateRoutingsLocked() {
if (routings.isEmpty()) {
unregisterReceiver()
ServiceNotification.stopForeground(this)
stopSelf()
} else {
fun updateRoutingsLocked() {
if (routings.isNotEmpty()) {
val upstream = upstream
if (upstream != null) {
var failed = false
@@ -56,13 +53,11 @@ class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Call
// system tethering already has working forwarding rules
// so it doesn't make sense to add additional forwarding rules
val routing = Routing(upstream, downstream).rule().forward().masquerade().dnsRedirect(dns)
if (routing.start()) routings[downstream] = routing else {
failed = true
routing.stop()
routings.remove(downstream)
}
routings[downstream] = routing
if (!routing.start()) failed = true
} catch (e: SocketException) {
e.printStackTrace()
routings.remove(downstream)
failed = true
}
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
@@ -76,6 +71,11 @@ class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Call
}
postIpNeighbourAvailable()
}
if (routings.isEmpty()) {
unregisterReceiver()
ServiceNotification.stopForeground(this)
stopSelf()
}
app.handler.post { binder.fragment?.adapter?.notifyDataSetChanged() }
}
@@ -113,21 +113,6 @@ class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Call
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
}
override fun onIpNeighbourAvailable(neighbours: Map<String, IpNeighbour>) {
this.neighbours = neighbours.values.toList()
}
override fun postIpNeighbourAvailable() {
val sizeLookup = neighbours.groupBy { it.dev }.mapValues { (_, neighbours) ->
neighbours
.filter { it.state != IpNeighbour.State.FAILED }
.distinctBy { it.lladdr }
.size
}
ServiceNotification.startForeground(this, synchronized(routings) {
routings.keys.associate { Pair(it, sizeLookup[it] ?: 0) }
})
}
override fun onDestroy() {
unregisterReceiver()
super.onDestroy()