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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user