Revert "Remove fallback upstream monitor"
This commit reverts 99e721bf7e.
Fixes #119.
This commit is contained in:
@@ -48,7 +48,7 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
|
|||||||
ipForward() // local only interfaces need to enable ip_forward
|
ipForward() // local only interfaces need to enable ip_forward
|
||||||
forward()
|
forward()
|
||||||
masquerade(masqueradeMode)
|
masquerade(masqueradeMode)
|
||||||
commit(true)
|
commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import androidx.preference.SwitchPreference
|
|||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.net.Routing.Companion.IPTABLES
|
import be.mygod.vpnhotspot.net.Routing.Companion.IPTABLES
|
||||||
import be.mygod.vpnhotspot.net.TetherOffloadManager
|
import be.mygod.vpnhotspot.net.TetherOffloadManager
|
||||||
|
import be.mygod.vpnhotspot.net.monitor.FallbackUpstreamMonitor
|
||||||
import be.mygod.vpnhotspot.net.monitor.IpMonitor
|
import be.mygod.vpnhotspot.net.monitor.IpMonitor
|
||||||
import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor
|
import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||||
@@ -115,6 +116,9 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
|echo iptables -nvx -L vpnhotspot_fwd
|
|echo iptables -nvx -L vpnhotspot_fwd
|
||||||
|$IPTABLES -nvx -L vpnhotspot_fwd
|
|$IPTABLES -nvx -L vpnhotspot_fwd
|
||||||
|echo
|
|echo
|
||||||
|
|echo iptables -nvx -L vpnhotspot_acl
|
||||||
|
|$IPTABLES -nvx -L vpnhotspot_acl
|
||||||
|
|echo
|
||||||
|echo logcat-su
|
|echo logcat-su
|
||||||
|logcat -d
|
|logcat -d
|
||||||
""".trimMargin())
|
""".trimMargin())
|
||||||
@@ -146,23 +150,24 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
|
|
||||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||||
when (preference.key) {
|
when (preference.key) {
|
||||||
UpstreamMonitor.KEY -> AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat().apply {
|
UpstreamMonitor.KEY, FallbackUpstreamMonitor.KEY ->
|
||||||
setArguments(preference.key, try {
|
AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat().apply {
|
||||||
NetworkInterface.getNetworkInterfaces().asSequence()
|
setArguments(preference.key, try {
|
||||||
.filter {
|
NetworkInterface.getNetworkInterfaces().asSequence()
|
||||||
try {
|
.filter {
|
||||||
it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty()
|
try {
|
||||||
} catch (_: SocketException) {
|
it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty()
|
||||||
false
|
} catch (_: SocketException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.map { it.name }.sorted().toList().toTypedArray()
|
||||||
.map { it.name }.sorted().toList().toTypedArray()
|
} catch (e: SocketException) {
|
||||||
} catch (e: SocketException) {
|
Timber.d(e)
|
||||||
Timber.d(e)
|
emptyArray<String>()
|
||||||
emptyArray<String>()
|
})
|
||||||
})
|
setTargetFragment(this@SettingsPreferenceFragment, 0)
|
||||||
setTargetFragment(this@SettingsPreferenceFragment, 0)
|
}.show(fragmentManager ?: return, preference.key)
|
||||||
}.show(fragmentManager ?: return, preference.key)
|
|
||||||
else -> super.onDisplayPreferenceDialog(preference)
|
else -> super.onDisplayPreferenceDialog(preference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import android.os.Build
|
|||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.R
|
import be.mygod.vpnhotspot.R
|
||||||
import be.mygod.vpnhotspot.net.monitor.DefaultNetworkMonitor
|
import be.mygod.vpnhotspot.net.monitor.FallbackUpstreamMonitor
|
||||||
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
|
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
|
||||||
import be.mygod.vpnhotspot.net.monitor.TrafficRecorder
|
import be.mygod.vpnhotspot.net.monitor.TrafficRecorder
|
||||||
import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor
|
import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor
|
||||||
@@ -52,6 +52,8 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
|||||||
it.execQuiet("while $IPTABLES -D FORWARD -j vpnhotspot_fwd; do done")
|
it.execQuiet("while $IPTABLES -D FORWARD -j vpnhotspot_fwd; do done")
|
||||||
it.execQuiet("$IPTABLES -F vpnhotspot_fwd")
|
it.execQuiet("$IPTABLES -F vpnhotspot_fwd")
|
||||||
it.execQuiet("$IPTABLES -X vpnhotspot_fwd")
|
it.execQuiet("$IPTABLES -X vpnhotspot_fwd")
|
||||||
|
it.execQuiet("$IPTABLES -F vpnhotspot_acl")
|
||||||
|
it.execQuiet("$IPTABLES -X vpnhotspot_acl")
|
||||||
it.execQuiet("while $IPTABLES -t nat -D POSTROUTING -j vpnhotspot_masquerade; do done")
|
it.execQuiet("while $IPTABLES -t nat -D POSTROUTING -j vpnhotspot_masquerade; do done")
|
||||||
it.execQuiet("$IPTABLES -t nat -F vpnhotspot_masquerade")
|
it.execQuiet("$IPTABLES -t nat -F vpnhotspot_masquerade")
|
||||||
it.execQuiet("$IPTABLES -t nat -X vpnhotspot_masquerade")
|
it.execQuiet("$IPTABLES -t nat -X vpnhotspot_masquerade")
|
||||||
@@ -120,17 +122,23 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
|||||||
*/
|
*/
|
||||||
inner class Subrouting(priority: Int, val upstream: String? = null) {
|
inner class Subrouting(priority: Int, val upstream: String? = null) {
|
||||||
val transaction = RootSession.beginTransaction().safeguard {
|
val transaction = RootSession.beginTransaction().safeguard {
|
||||||
if (upstream != null) ipRule("from all", downstream, upstream, priority)
|
if (upstream != null) {
|
||||||
fun simpleMasquerade() {
|
ipRule("from all", downstream, upstream, priority)
|
||||||
// note: specifying -i wouldn't work for POSTROUTING
|
iptablesInsert("vpnhotspot_fwd -i $downstream -o $upstream -j vpnhotspot_acl")
|
||||||
iptablesAdd(if (upstream == null) "vpnhotspot_masquerade -s $hostSubnet -j MASQUERADE" else
|
iptablesInsert("vpnhotspot_fwd -i $upstream -o $downstream -m state --state ESTABLISHED,RELATED -j vpnhotspot_acl")
|
||||||
"vpnhotspot_masquerade -s $hostSubnet -o $upstream -j MASQUERADE", "nat")
|
} else {
|
||||||
|
iptablesInsert("vpnhotspot_fwd -i $downstream -j vpnhotspot_acl")
|
||||||
|
iptablesInsert("vpnhotspot_fwd -o $downstream -m state --state ESTABLISHED,RELATED -j vpnhotspot_acl")
|
||||||
}
|
}
|
||||||
@TargetApi(28) when (masqueradeMode) {
|
@TargetApi(28) when (masqueradeMode) {
|
||||||
MasqueradeMode.None -> { } // nothing to be done here
|
MasqueradeMode.None -> { } // nothing to be done here
|
||||||
MasqueradeMode.Simple -> simpleMasquerade()
|
MasqueradeMode.Simple -> {
|
||||||
// fallback is only needed for repeater on API 23
|
// note: specifying -i wouldn't work for POSTROUTING
|
||||||
MasqueradeMode.Netd -> if (upstream == null) simpleMasquerade() else {
|
iptablesAdd(if (upstream == null) "vpnhotspot_masquerade -s $hostSubnet -j MASQUERADE" else
|
||||||
|
"vpnhotspot_masquerade -s $hostSubnet -o $upstream -j MASQUERADE", "nat")
|
||||||
|
}
|
||||||
|
MasqueradeMode.Netd -> {
|
||||||
|
check(upstream != null) // fallback is only needed for repeater on API 23 < 28
|
||||||
/**
|
/**
|
||||||
* 0 means that there are no interface addresses coming after, which is unused anyway.
|
* 0 means that there are no interface addresses coming after, which is unused anyway.
|
||||||
*
|
*
|
||||||
@@ -166,7 +174,7 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
|||||||
override fun onLost() = synchronized(this@Routing) {
|
override fun onLost() = synchronized(this@Routing) {
|
||||||
val subrouting = subrouting ?: return
|
val subrouting = subrouting ?: return
|
||||||
// we could be removing fallback subrouting which no collision could ever happen, check before removing
|
// we could be removing fallback subrouting which no collision could ever happen, check before removing
|
||||||
if (subrouting.upstream != null) check(upstreams.remove(subrouting.upstream))
|
subrouting.upstream?.let { check(upstreams.remove(it)) }
|
||||||
subrouting.transaction.revert()
|
subrouting.transaction.revert()
|
||||||
this.subrouting = null
|
this.subrouting = null
|
||||||
dns = emptyList()
|
dns = emptyList()
|
||||||
@@ -191,8 +199,8 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
|||||||
private inner class Client(private val ip: Inet4Address, mac: Long) : AutoCloseable {
|
private inner class Client(private val ip: Inet4Address, mac: Long) : AutoCloseable {
|
||||||
private val transaction = RootSession.beginTransaction().safeguard {
|
private val transaction = RootSession.beginTransaction().safeguard {
|
||||||
val address = ip.hostAddress
|
val address = ip.hostAddress
|
||||||
iptablesInsert("vpnhotspot_fwd -i $downstream -s $address -j ACCEPT")
|
iptablesInsert("vpnhotspot_acl -i $downstream -s $address -j ACCEPT")
|
||||||
iptablesInsert("vpnhotspot_fwd -o $downstream -d $address -m state --state ESTABLISHED,RELATED -j ACCEPT")
|
iptablesInsert("vpnhotspot_acl -o $downstream -d $address -j ACCEPT")
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -261,6 +269,7 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
|||||||
|
|
||||||
fun forward() {
|
fun forward() {
|
||||||
transaction.execQuiet("$IPTABLES -N vpnhotspot_fwd")
|
transaction.execQuiet("$IPTABLES -N vpnhotspot_fwd")
|
||||||
|
transaction.execQuiet("$IPTABLES -N vpnhotspot_acl")
|
||||||
transaction.iptablesInsert("FORWARD -j vpnhotspot_fwd")
|
transaction.iptablesInsert("FORWARD -j vpnhotspot_fwd")
|
||||||
transaction.iptablesAdd("vpnhotspot_fwd -i $downstream ! -o $downstream -j DROP") // ensure blocking works
|
transaction.iptablesAdd("vpnhotspot_fwd -i $downstream ! -o $downstream -j DROP") // ensure blocking works
|
||||||
// the real forwarding filters will be added in Subrouting when clients are connected
|
// the real forwarding filters will be added in Subrouting when clients are connected
|
||||||
@@ -306,15 +315,14 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
|||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
IpNeighbourMonitor.unregisterCallback(this)
|
IpNeighbourMonitor.unregisterCallback(this)
|
||||||
DefaultNetworkMonitor.unregisterCallback(fallbackUpstream)
|
FallbackUpstreamMonitor.unregisterCallback(fallbackUpstream)
|
||||||
UpstreamMonitor.unregisterCallback(upstream)
|
UpstreamMonitor.unregisterCallback(upstream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun commit(localOnly: Boolean = false) {
|
fun commit() {
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
Timber.i("Started routing for $downstream by $caller")
|
Timber.i("Started routing for $downstream by $caller")
|
||||||
@TargetApi(28)
|
FallbackUpstreamMonitor.registerCallback(fallbackUpstream)
|
||||||
if (localOnly || masqueradeMode != MasqueradeMode.Netd) DefaultNetworkMonitor.registerCallback(fallbackUpstream)
|
|
||||||
UpstreamMonitor.registerCallback(upstream)
|
UpstreamMonitor.registerCallback(upstream)
|
||||||
IpNeighbourMonitor.registerCallback(this)
|
IpNeighbourMonitor.registerCallback(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package be.mygod.vpnhotspot.net.monitor
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
|
|
||||||
|
abstract class FallbackUpstreamMonitor private constructor() : UpstreamMonitor() {
|
||||||
|
companion object : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
const val KEY = "service.upstream.fallback"
|
||||||
|
|
||||||
|
init {
|
||||||
|
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateMonitor(): UpstreamMonitor {
|
||||||
|
val upstream = app.pref.getString(KEY, null)
|
||||||
|
return if (upstream.isNullOrEmpty()) DefaultNetworkMonitor else InterfaceMonitor(upstream)
|
||||||
|
}
|
||||||
|
private var monitor = generateMonitor()
|
||||||
|
|
||||||
|
fun registerCallback(callback: Callback) = synchronized(this) { monitor.registerCallback(callback) }
|
||||||
|
fun unregisterCallback(callback: Callback) = synchronized(this) { monitor.unregisterCallback(callback) }
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||||
|
if (key == KEY) synchronized(this) {
|
||||||
|
val old = monitor
|
||||||
|
val callbacks = synchronized(old) {
|
||||||
|
val callbacks = old.callbacks.toList()
|
||||||
|
old.callbacks.clear()
|
||||||
|
old.destroyLocked()
|
||||||
|
callbacks
|
||||||
|
}
|
||||||
|
val new = generateMonitor()
|
||||||
|
monitor = new
|
||||||
|
for (callback in callbacks) {
|
||||||
|
callback.onLost()
|
||||||
|
new.registerCallback(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ object TrafficRecorder {
|
|||||||
private fun doUpdate(timestamp: Long) {
|
private fun doUpdate(timestamp: Long) {
|
||||||
val oldRecords = LongSparseArray<TrafficRecord>()
|
val oldRecords = LongSparseArray<TrafficRecord>()
|
||||||
loop@ for (line in RootSession.use {
|
loop@ for (line in RootSession.use {
|
||||||
val command = "$IPTABLES -nvx -L vpnhotspot_fwd"
|
val command = "$IPTABLES -nvx -L vpnhotspot_acl"
|
||||||
val result = it.execQuiet(command)
|
val result = it.execQuiet(command)
|
||||||
val message = RootSession.checkOutput(command, result, false, false)
|
val message = RootSession.checkOutput(command, result, false, false)
|
||||||
if (result.err.isNotEmpty()) Timber.i(message)
|
if (result.err.isNotEmpty()) Timber.i(message)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M5,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4L1,6v6h6L7,6L5,6L5,2zM9,16c0,1.3 0.84,2.4 2,2.82L11,23h2v-4.18c1.16,-0.41 2,-1.51 2,-2.82v-2L9,14v2zM1,16c0,1.3 0.84,2.4 2,2.82L3,23h2v-4.18C6.16,18.4 7,17.3 7,16v-2L1,14v2zM21,6L21,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4h-2v6h6L23,6h-2zM13,2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v4L9,6v6h6L15,6h-2L13,2zM17,16c0,1.3 0.84,2.4 2,2.82L19,23h2v-4.18c1.16,-0.41 2,-1.51 2,-2.82v-2h-6v2z"/>
|
||||||
|
</vector>
|
||||||
@@ -99,6 +99,8 @@
|
|||||||
<string name="settings_service_ip_monitor_poll_root">轮询 (root)</string>
|
<string name="settings_service_ip_monitor_poll_root">轮询 (root)</string>
|
||||||
<string name="settings_service_upstream">上游网络接口</string>
|
<string name="settings_service_upstream">上游网络接口</string>
|
||||||
<string name="settings_service_upstream_auto">自动检测系统 VPN</string>
|
<string name="settings_service_upstream_auto">自动检测系统 VPN</string>
|
||||||
|
<string name="settings_upstream_fallback">备用上游接口</string>
|
||||||
|
<string name="settings_upstream_fallback_auto">自动检测系统默认网络</string>
|
||||||
<string name="settings_service_clean">清理/重新应用路由规则</string>
|
<string name="settings_service_clean">清理/重新应用路由规则</string>
|
||||||
<string name="settings_service_clean_summary">将修改的设置应用到当前启用的服务上。也可用于修复偶尔会发生的竞态条件。</string>
|
<string name="settings_service_clean_summary">将修改的设置应用到当前启用的服务上。也可用于修复偶尔会发生的竞态条件。</string>
|
||||||
<string name="settings_service_dhcp_workaround">尝试修复 DHCP</string>
|
<string name="settings_service_dhcp_workaround">尝试修复 DHCP</string>
|
||||||
|
|||||||
@@ -104,6 +104,8 @@
|
|||||||
<string name="settings_service_ip_monitor_poll_root">Poll with root</string>
|
<string name="settings_service_ip_monitor_poll_root">Poll with root</string>
|
||||||
<string name="settings_service_upstream">Upstream network interface</string>
|
<string name="settings_service_upstream">Upstream network interface</string>
|
||||||
<string name="settings_service_upstream_auto">Auto detect system VPN</string>
|
<string name="settings_service_upstream_auto">Auto detect system VPN</string>
|
||||||
|
<string name="settings_upstream_fallback">Fallback upstream interface</string>
|
||||||
|
<string name="settings_upstream_fallback_auto">Auto detect system default network</string>
|
||||||
<string name="settings_service_dhcp_workaround">Enable DHCP workaround</string>
|
<string name="settings_service_dhcp_workaround">Enable DHCP workaround</string>
|
||||||
<string name="settings_service_dhcp_workaround_summary">Use this if clients cannot obtain IP addresses.</string>
|
<string name="settings_service_dhcp_workaround_summary">Use this if clients cannot obtain IP addresses.</string>
|
||||||
<string name="settings_service_clean">Clean/reapply routing rules</string>
|
<string name="settings_service_clean">Clean/reapply routing rules</string>
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
app:icon="@drawable/ic_action_settings_ethernet"
|
app:icon="@drawable/ic_action_settings_ethernet"
|
||||||
app:title="@string/settings_service_upstream"
|
app:title="@string/settings_service_upstream"
|
||||||
app:summary="@string/settings_service_upstream_auto"/>
|
app:summary="@string/settings_service_upstream_auto"/>
|
||||||
|
<be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreference
|
||||||
|
app:key="service.upstream.fallback"
|
||||||
|
app:icon="@drawable/ic_action_settings_input_component"
|
||||||
|
app:title="@string/settings_upstream_fallback"
|
||||||
|
app:summary="@string/settings_upstream_fallback_auto"/>
|
||||||
<com.takisoft.preferencex.SimpleMenuPreference
|
<com.takisoft.preferencex.SimpleMenuPreference
|
||||||
app:key="service.masqueradeMode"
|
app:key="service.masqueradeMode"
|
||||||
app:icon="@drawable/ic_social_people"
|
app:icon="@drawable/ic_social_people"
|
||||||
|
|||||||
Reference in New Issue
Block a user