From 62449a98ea5d0bae81fff334130ef602c7bbefdc Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 5 Jan 2018 01:33:03 +0800 Subject: [PATCH] Various bugfix for Wi-Fi direct mode --- .../be/mygod/vpnhotspot/HotspotService.kt | 39 ++++++++++--------- .../java/be/mygod/vpnhotspot/MainActivity.kt | 2 +- .../main/java/be/mygod/vpnhotspot/Routing.kt | 18 +++++++-- .../main/java/be/mygod/vpnhotspot/Utils.kt | 4 +- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt index 2886264e..bd0e3b31 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt @@ -63,21 +63,9 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { val service get() = this@HotspotService var data: MainActivity.Data? = null - fun shutdown() { - when (status) { - Status.ACTIVE_P2P -> p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener { - override fun onSuccess() = clean() - override fun onFailure(reason: Int) { - if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone - Toast.makeText(this@HotspotService, "Failed to remove P2P group (${formatReason(reason)})", - Toast.LENGTH_SHORT).show() - LocalBroadcastManager.getInstance(this@HotspotService) - .sendBroadcast(Intent(STATUS_CHANGED)) - } - } - }) - else -> clean() - } + fun shutdown() = when (status) { + Status.ACTIVE_P2P -> removeGroup() + else -> clean() } } @@ -199,10 +187,10 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { return START_NOT_STICKY } - private fun startFailure(msg: String) { + private fun startFailure(msg: String, group: WifiP2pGroup? = null) { Toast.makeText(this@HotspotService, msg, Toast.LENGTH_SHORT).show() showNotification() - clean() + if (group != null) removeGroup() else clean() } private fun doStart() = p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener { override fun onFailure(reason: Int) = startFailure("Failed to create P2P group (${formatReason(reason)})") @@ -234,15 +222,28 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { val routing = try { Routing(upstream, downstream, owner) } catch (_: Routing.InterfaceNotFoundException) { - startFailure(getString(R.string.exception_interface_not_found)) + startFailure(getString(R.string.exception_interface_not_found), group) return }.p2pRule().forward().dnsRedirect(dns) if (routing.start()) { this.routing = routing doStart(group) - } else startFailure("Something went wrong, please check logcat.") + } else startFailure("Something went wrong, please check logcat.", group) } + private fun removeGroup() { + p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener { + override fun onSuccess() = clean() + override fun onFailure(reason: Int) { + if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone + Toast.makeText(this@HotspotService, "Failed to remove P2P group (${formatReason(reason)})", + Toast.LENGTH_SHORT).show() + status = Status.ACTIVE_P2P + LocalBroadcastManager.getInstance(this@HotspotService).sendBroadcast(Intent(STATUS_CHANGED)) + } + } + }) + } private fun unregisterReceiver() { if (receiverRegistered) { unregisterReceiver(receiver) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt index d36a0a07..86ed109b 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt @@ -87,7 +87,7 @@ class MainActivity : AppCompatActivity(), ServiceConnection, Toolbar.OnMenuItemC } holder.binding.device = device holder.binding.ipAddress = when (position) { - 0 -> binder?.service?.routing?.hostAddress + 0 -> binder?.service?.routing?.hostAddress?.hostAddress else -> arpCache[device?.deviceAddress] } holder.binding.executePendingBindings() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/Routing.kt b/mobile/src/main/java/be/mygod/vpnhotspot/Routing.kt index 7fbc10cc..ccef2eb4 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/Routing.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/Routing.kt @@ -20,7 +20,7 @@ class Routing(private val upstream: String, val downstream: String, ownerAddress class InterfaceNotFoundException : IOException() - val hostAddress: String + val hostAddress: InetAddress private val subnetPrefixLength: Short private val startScript = LinkedList() private val stopScript = LinkedList() @@ -28,19 +28,28 @@ class Routing(private val upstream: String, val downstream: String, ownerAddress val address = NetworkInterface.getByName(downstream)?.interfaceAddresses ?.singleOrNull { if (ownerAddress == null) it.address is Inet4Address else it.address == ownerAddress } ?: throw InterfaceNotFoundException() - hostAddress = address.address.hostAddress + hostAddress = address.address subnetPrefixLength = address.networkPrefixLength } fun p2pRule(): Routing { + // clear suffix bits + val address = hostAddress.address + var done = subnetPrefixLength.toInt() + while (done < address.size shl 3) { + val index = done shr 3 + address[index] = (address[index].toInt() and (0x7f00 shr (done and 7))).toByte() + done = (index + 1) shl 3 + } + val hostAddress = InetAddress.getByAddress(address).hostAddress startScript.add("echo 1 >/proc/sys/net/ipv4/ip_forward") // Wi-Fi direct doesn't enable ip_forward startScript.add("ip route add default dev $upstream scope link table 62") startScript.add("ip route add $hostAddress/$subnetPrefixLength dev $downstream scope link table 62") startScript.add("ip route add broadcast 255.255.255.255 dev $downstream scope link table 62") startScript.add("ip rule add iif $downstream lookup 62") stopScript.addFirst("ip route del default dev $upstream scope link table 62") - stopScript.addFirst("ip route del $hostAddress/$subnetPrefixLength dev $downstream scope link table 62") - stopScript.addFirst("ip route del broadcast 255.255.255.255 dev $downstream scope link table 62") + // removing each rule may fail if downstream is already removed + stopScript.addFirst("ip route flush table 62") stopScript.addFirst("ip rule del iif $downstream lookup 62") return this } @@ -65,6 +74,7 @@ class Routing(private val upstream: String, val downstream: String, ownerAddress } fun dnsRedirect(dns: String): Routing { + val hostAddress = hostAddress.hostAddress startScript.add("iptables -t nat -A PREROUTING -i $downstream -p tcp -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") diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt b/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt index 8b2220b6..ea7b7ae3 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt @@ -23,8 +23,8 @@ fun Bundle.put(key: String, map: Array): Bundle { return this } -const val NOISYSU_TAG = "NoisySU" -const val NOISYSU_SUFFIX = "SUCCESS\n" +private const val NOISYSU_TAG = "NoisySU" +private const val NOISYSU_SUFFIX = "SUCCESS\n" fun loggerSuStream(command: String): InputStream { val process = ProcessBuilder("su", "-c", command) .redirectErrorStream(true)