Add DHCP workaround
Thanks to petergunn666 for debugging this with me.
This commit is contained in:
@@ -18,7 +18,6 @@ import io.fabric.sdk.android.Fabric
|
|||||||
class App : Application() {
|
class App : Application() {
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
|
const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
|
||||||
private const val KEY_MASQUERADE = "service.masquerade"
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
lateinit var app: App
|
lateinit var app: App
|
||||||
@@ -50,7 +49,8 @@ class App : Application() {
|
|||||||
val result = pref.getString(KEY_OPERATING_CHANNEL, null)?.toIntOrNull() ?: 0
|
val result = pref.getString(KEY_OPERATING_CHANNEL, null)?.toIntOrNull() ?: 0
|
||||||
return if (result in 1..165) result else 0
|
return if (result in 1..165) result else 0
|
||||||
}
|
}
|
||||||
val masquerade: Boolean get() = pref.getBoolean(KEY_MASQUERADE, true)
|
val masquerade: Boolean get() = pref.getBoolean("service.masquerade", true)
|
||||||
|
val dhcpWorkaround: Boolean get() = pref.getBoolean("service.dhcpWorkaround", false)
|
||||||
|
|
||||||
val cleanRoutings = Event0()
|
val cleanRoutings = Event0()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,15 +40,18 @@ class LocalOnlyInterfaceManager(val downstream: String) : UpstreamMonitor.Callba
|
|||||||
private fun initRouting(upstream: String? = null, owner: InterfaceAddress? = null,
|
private fun initRouting(upstream: String? = null, owner: InterfaceAddress? = null,
|
||||||
dns: List<InetAddress> = this.dns) {
|
dns: List<InetAddress> = this.dns) {
|
||||||
try {
|
try {
|
||||||
val routing = Routing(upstream, downstream, owner)
|
|
||||||
this.routing = routing
|
|
||||||
this.dns = dns
|
this.dns = dns
|
||||||
val strict = app.pref.getBoolean("service.repeater.strict", false)
|
this.routing = Routing(upstream, downstream, owner).apply {
|
||||||
if (strict && upstream == null) return // in this case, nothing to be done
|
val strict = app.pref.getBoolean("service.repeater.strict", false)
|
||||||
routing.ipForward() // local only interfaces need not enable ip_forward
|
if (strict && upstream == null) return@apply // in this case, nothing to be done
|
||||||
.rule().forward(strict)
|
if (app.dhcpWorkaround) dhcpWorkaround()
|
||||||
if (app.masquerade) routing.masquerade(strict)
|
ipForward() // local only interfaces need to enable ip_forward
|
||||||
if (!routing.dnsRedirect(dns).start()) SmartSnackbar.make(R.string.noisy_su_failure).show()
|
rule()
|
||||||
|
forward(strict)
|
||||||
|
if (app.masquerade) masquerade(strict)
|
||||||
|
dnsRedirect(dns)
|
||||||
|
if (!start()) SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||||
|
}
|
||||||
} catch (e: SocketException) {
|
} catch (e: SocketException) {
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
Crashlytics.logException(e)
|
Crashlytics.logException(e)
|
||||||
|
|||||||
@@ -47,14 +47,17 @@ class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callbac
|
|||||||
var failed = false
|
var failed = false
|
||||||
for ((downstream, value) in routings) if (value == null || value.upstream != upstream)
|
for ((downstream, value) in routings) if (value == null || value.upstream != upstream)
|
||||||
try {
|
try {
|
||||||
// system tethering already has working forwarding rules
|
routings[downstream] = Routing(upstream, downstream).apply {
|
||||||
// so it doesn't make sense to add additional forwarding rules
|
if (app.dhcpWorkaround) dhcpWorkaround()
|
||||||
val routing = Routing(upstream, downstream).rule().forward()
|
// system tethering already has working forwarding rules
|
||||||
if (app.masquerade) routing.masquerade()
|
// so it doesn't make sense to add additional forwarding rules
|
||||||
routing.dnsRedirect(dns)
|
rule()
|
||||||
if (app.pref.getBoolean("service.disableIpv6", false)) routing.disableIpv6()
|
forward()
|
||||||
routings[downstream] = routing
|
if (app.masquerade) masquerade()
|
||||||
if (!routing.start()) failed = true
|
dnsRedirect(dns)
|
||||||
|
if (app.pref.getBoolean("service.disableIpv6", false)) disableIpv6()
|
||||||
|
if (!start()) failed = true
|
||||||
|
}
|
||||||
} catch (e: SocketException) {
|
} catch (e: SocketException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
Crashlytics.logException(e)
|
Crashlytics.logException(e)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
|||||||
"$IPTABLES -t nat -F vpnhotspot_masquerade",
|
"$IPTABLES -t nat -F vpnhotspot_masquerade",
|
||||||
"$IPTABLES -t nat -X vpnhotspot_masquerade",
|
"$IPTABLES -t nat -X vpnhotspot_masquerade",
|
||||||
"quiet while ip rule del priority 17900; do done",
|
"quiet while ip rule del priority 17900; do done",
|
||||||
|
"quiet while ip rule del iif lo uidrange 0-0 lookup local_network priority 11000; do done",
|
||||||
report = false)
|
report = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,15 +41,13 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
|||||||
private val stopScript = LinkedList<String>()
|
private val stopScript = LinkedList<String>()
|
||||||
var started = false
|
var started = false
|
||||||
|
|
||||||
fun ipForward(): Routing {
|
fun ipForward() {
|
||||||
startScript.add("echo 1 >/proc/sys/net/ipv4/ip_forward")
|
startScript.add("echo 1 >/proc/sys/net/ipv4/ip_forward")
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableIpv6(): Routing {
|
fun disableIpv6() {
|
||||||
startScript.add("echo 1 >/proc/sys/net/ipv6/conf/$downstream/disable_ipv6")
|
startScript.add("echo 1 >/proc/sys/net/ipv6/conf/$downstream/disable_ipv6")
|
||||||
stopScript.add("echo 0 >/proc/sys/net/ipv6/conf/$downstream/disable_ipv6")
|
stopScript.add("echo 0 >/proc/sys/net/ipv6/conf/$downstream/disable_ipv6")
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,16 +56,15 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
|||||||
*
|
*
|
||||||
* Source: https://android.googlesource.com/platform/system/netd/+/b9baf26/server/RouteController.cpp#65
|
* Source: https://android.googlesource.com/platform/system/netd/+/b9baf26/server/RouteController.cpp#65
|
||||||
*/
|
*/
|
||||||
fun rule(): Routing {
|
fun rule() {
|
||||||
if (upstream != null) {
|
if (upstream != null) {
|
||||||
startScript.add("ip rule add from all iif $downstream lookup $upstream priority 17900")
|
startScript.add("ip rule add from all iif $downstream lookup $upstream priority 17900")
|
||||||
// by the time stopScript is called, table entry for upstream may already get removed
|
// by the time stopScript is called, table entry for upstream may already get removed
|
||||||
stopScript.addFirst("ip rule del from all iif $downstream priority 17900")
|
stopScript.addFirst("ip rule del from all iif $downstream priority 17900")
|
||||||
}
|
}
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forward(strict: Boolean = true): Routing {
|
fun forward(strict: Boolean = true) {
|
||||||
startScript.add("quiet $IPTABLES -N vpnhotspot_fwd 2>/dev/null")
|
startScript.add("quiet $IPTABLES -N vpnhotspot_fwd 2>/dev/null")
|
||||||
if (strict) {
|
if (strict) {
|
||||||
check(upstream != null)
|
check(upstream != null)
|
||||||
@@ -84,10 +82,9 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
|||||||
}
|
}
|
||||||
startScript.add("$IPTABLES -I FORWARD -j vpnhotspot_fwd")
|
startScript.add("$IPTABLES -I FORWARD -j vpnhotspot_fwd")
|
||||||
stopScript.addFirst("$IPTABLES -D FORWARD -j vpnhotspot_fwd")
|
stopScript.addFirst("$IPTABLES -D FORWARD -j vpnhotspot_fwd")
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun masquerade(strict: Boolean = true): Routing {
|
fun masquerade(strict: Boolean = true) {
|
||||||
val hostSubnet = "${hostAddress.address.hostAddress}/${hostAddress.networkPrefixLength}"
|
val hostSubnet = "${hostAddress.address.hostAddress}/${hostAddress.networkPrefixLength}"
|
||||||
startScript.add("quiet $IPTABLES -t nat -N vpnhotspot_masquerade 2>/dev/null")
|
startScript.add("quiet $IPTABLES -t nat -N vpnhotspot_masquerade 2>/dev/null")
|
||||||
// note: specifying -i wouldn't work for POSTROUTING
|
// note: specifying -i wouldn't work for POSTROUTING
|
||||||
@@ -101,10 +98,9 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
|||||||
}
|
}
|
||||||
startScript.add("$IPTABLES -t nat -I POSTROUTING -j vpnhotspot_masquerade")
|
startScript.add("$IPTABLES -t nat -I POSTROUTING -j vpnhotspot_masquerade")
|
||||||
stopScript.addFirst("$IPTABLES -t nat -D POSTROUTING -j vpnhotspot_masquerade")
|
stopScript.addFirst("$IPTABLES -t nat -D POSTROUTING -j vpnhotspot_masquerade")
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dnsRedirect(dnses: List<InetAddress>): Routing {
|
fun dnsRedirect(dnses: List<InetAddress>) {
|
||||||
val hostAddress = hostAddress.address.hostAddress
|
val hostAddress = hostAddress.address.hostAddress
|
||||||
val dns = dnses.firstOrNull { it is Inet4Address }?.hostAddress ?: app.pref.getString("service.dns", "8.8.8.8")
|
val dns = dnses.firstOrNull { it is Inet4Address }?.hostAddress ?: app.pref.getString("service.dns", "8.8.8.8")
|
||||||
debugLog("Routing", "Using $dns from ($dnses)")
|
debugLog("Routing", "Using $dns from ($dnses)")
|
||||||
@@ -112,7 +108,19 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
|||||||
startScript.add("$IPTABLES -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
startScript.add("$IPTABLES -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
||||||
stopScript.addFirst("$IPTABLES -t nat -D PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
stopScript.addFirst("$IPTABLES -t nat -D PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
||||||
stopScript.addFirst("$IPTABLES -t nat -D PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
stopScript.addFirst("$IPTABLES -t nat -D PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
||||||
return this
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similarly, assuming RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 11000.
|
||||||
|
* Normally this is used to forward packets from remote to local, but it works anyways. It just needs to be before
|
||||||
|
* RULE_PRIORITY_SECURE_VPN = 12000. It would be great if we can gain better understanding into why this is only
|
||||||
|
* needed on some of the devices but not others.
|
||||||
|
*
|
||||||
|
* Source: https://android.googlesource.com/platform/system/netd/+/b9baf26/server/RouteController.cpp#57
|
||||||
|
*/
|
||||||
|
fun dhcpWorkaround() {
|
||||||
|
startScript.add("ip rule add iif lo uidrange 0-0 lookup local_network priority 11000")
|
||||||
|
stopScript.addFirst("ip rule del iif lo uidrange 0-0 lookup local_network priority 11000")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun start(): Boolean {
|
fun start(): Boolean {
|
||||||
|
|||||||
6
mobile/src/main/res/drawable/ic_action_build.xml
Normal file
6
mobile/src/main/res/drawable/ic_action_build.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"/>
|
||||||
|
</vector>
|
||||||
@@ -71,6 +71,8 @@
|
|||||||
<string name="settings_service_upstream_auto">自动检测系统 VPN</string>
|
<string name="settings_service_upstream_auto">自动检测系统 VPN</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_summary">如果设备无法获取 IP 地址,尝试打开这个选项。</string>
|
||||||
<string name="settings_misc">杂项</string>
|
<string name="settings_misc">杂项</string>
|
||||||
<string name="settings_misc_logcat">导出调试信息</string>
|
<string name="settings_misc_logcat">导出调试信息</string>
|
||||||
<string name="settings_misc_logcat_summary">这种非常有用哇</string>
|
<string name="settings_misc_logcat_summary">这种非常有用哇</string>
|
||||||
|
|||||||
@@ -74,6 +74,8 @@
|
|||||||
<string name="settings_service_dns">Fallback DNS server[:port]</string>
|
<string name="settings_service_dns">Fallback DNS server[:port]</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_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_clean">Clean/reapply routing rules</string>
|
<string name="settings_service_clean">Clean/reapply routing rules</string>
|
||||||
<string name="settings_service_clean_summary">Update changed settings to current active services. Can also fix rare
|
<string name="settings_service_clean_summary">Update changed settings to current active services. Can also fix rare
|
||||||
race conditions.</string>
|
race conditions.</string>
|
||||||
|
|||||||
@@ -40,6 +40,11 @@
|
|||||||
android:summary="@string/settings_service_upstream_auto"
|
android:summary="@string/settings_service_upstream_auto"
|
||||||
android:hint="@string/settings_service_upstream_auto"
|
android:hint="@string/settings_service_upstream_auto"
|
||||||
android:singleLine="true"/>
|
android:singleLine="true"/>
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="service.dhcpWorkaround"
|
||||||
|
android:icon="@drawable/ic_action_build"
|
||||||
|
android:title="@string/settings_service_dhcp_workaround"
|
||||||
|
android:summary="@string/settings_service_disable_ipv6_summary"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/settings_misc">
|
android:title="@string/settings_misc">
|
||||||
|
|||||||
Reference in New Issue
Block a user