diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index 6173b525..cd422975 100644 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + () { - companion object { - private val spaces = " +".toPattern() - private val mac = "^([0-9a-f]{2}:){5}[0-9a-f]{2}$".toPattern() - } - - init { - File("/proc/net/arp").bufferedReader().useLines { - for (line in it) { - val parts = line.split(spaces) - // IP address HW type Flags HW address Mask Device - if (parts.size >= 4 && (downstream == null || parts.getOrNull(5) == downstream) && - mac.matcher(parts[3]).matches()) put(parts[3], parts[0]) - } - } - } -} diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt index 570162f3..6bffdbfb 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt @@ -16,6 +16,7 @@ import android.support.v4.content.LocalBroadcastManager import android.util.Log import android.widget.Toast import be.mygod.vpnhotspot.App.Companion.app +import java.net.NetworkInterface class HotspotService : Service(), WifiP2pManager.ChannelListener { companion object { @@ -63,26 +64,7 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { val info = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO) val net = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO) val group = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP) - val hostAddress = info.groupOwnerAddress?.hostAddress - val downstream = group.`interface` - if (info.groupFormed && info.isGroupOwner && - downstream != null && hostAddress != null && this.downstream == null) { - this.downstream = downstream - this.hostAddress = hostAddress - if (noisySu("echo 1 >/proc/sys/net/ipv4/ip_forward", - "ip route add default dev $upstream scope link table 62", - "ip route add $hostAddress/$subnetPrefixLength dev $downstream scope link table 62", - "ip route add broadcast 255.255.255.255 dev $downstream scope link table 62", - "ip rule add from $hostAddress/$subnetPrefixLength lookup 62", - "iptables -N vpnhotspot_fwd", - "iptables -A vpnhotspot_fwd -i $upstream -o $downstream -m state --state ESTABLISHED,RELATED -j ACCEPT", - "iptables -A vpnhotspot_fwd -i $downstream -o $upstream -j ACCEPT", - "iptables -I FORWARD -j vpnhotspot_fwd", - "iptables -t nat -A PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns", - "iptables -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")) { - doStart(group) - } else startFailure("Something went wrong, please check logcat.") - } + if (downstream == null) onGroupCreated(info, group) this@HotspotService.group = group binder.data?.onGroupChanged() showNotification(group) @@ -99,7 +81,7 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { * https://android.googlesource.com/platform/frameworks/base/+/android-4.0.1_r1/wifi/java/android/net/wifi/p2p/WifiP2pService.java#1028 * https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/a8d5e40/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java#2547 */ - private val subnetPrefixLength get() = app.pref.getString("service.subnetPrefixLength", "24") + private var subnetPrefixLength: Short = 24 private val dns get() = app.pref.getString("service.dns", "8.8.8.8:53") var status = Status.IDLE @@ -183,6 +165,35 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { Intent(this, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT)) .build()) + private fun onGroupCreated(info: WifiP2pInfo, group: WifiP2pGroup) { + val owner = info.groupOwnerAddress + val hostAddress = owner?.hostAddress + val downstream = group.`interface` + if (!info.groupFormed || !info.isGroupOwner || downstream == null || hostAddress == null) return + this.downstream = downstream + this.hostAddress = hostAddress + var subnetPrefixLength = NetworkInterface.getByName(downstream)?.interfaceAddresses + ?.singleOrNull { it.address == owner }?.networkPrefixLength + if (subnetPrefixLength == null) { + Log.w(TAG, "Unable to find prefix length of interface $downstream, 24 is assumed") + subnetPrefixLength = 24 + } + this.subnetPrefixLength = subnetPrefixLength + if (noisySu("echo 1 >/proc/sys/net/ipv4/ip_forward", + "ip route add default dev $upstream scope link table 62", + "ip route add $hostAddress/$subnetPrefixLength dev $downstream scope link table 62", + "ip route add broadcast 255.255.255.255 dev $downstream scope link table 62", + "ip rule add from $hostAddress/$subnetPrefixLength lookup 62", + "iptables -N vpnhotspot_fwd", + "iptables -A vpnhotspot_fwd -i $upstream -o $downstream -m state --state ESTABLISHED,RELATED -j ACCEPT", + "iptables -A vpnhotspot_fwd -i $downstream -o $upstream -j ACCEPT", + "iptables -I FORWARD -j vpnhotspot_fwd", + "iptables -t nat -A PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns", + "iptables -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")) { + doStart(group) + } else startFailure("Something went wrong, please check logcat.") + } + private fun clean() { 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 5fe35d9e..140121a6 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt @@ -66,14 +66,14 @@ class MainActivity : AppCompatActivity(), ServiceConnection, Toolbar.OnMenuItemC inner class ClientAdapter : RecyclerView.Adapter() { private var owner: WifiP2pDevice? = null private lateinit var clients: MutableCollection - private lateinit var arpCache: ArpCache + private lateinit var arpCache: Map fun fetchClients() { if (data.running) { val binder = binder!! owner = binder.service.group.owner clients = binder.service.group.clientList - arpCache = ArpCache(binder.service.downstream) + arpCache = NetUtils.arp(binder.service.downstream) } else owner = null notifyDataSetChanged() // recreate everything } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/NetUtils.kt b/mobile/src/main/java/be/mygod/vpnhotspot/NetUtils.kt new file mode 100644 index 00000000..ee4f0080 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/NetUtils.kt @@ -0,0 +1,17 @@ +package be.mygod.vpnhotspot + +import java.io.File + +object NetUtils { + private val spaces = " +".toPattern() + private val mac = "^([0-9a-f]{2}:){5}[0-9a-f]{2}$".toPattern() + + fun arp(iface: String? = null) = File("/proc/net/arp").bufferedReader().useLines { + // IP address HW type Flags HW address Mask Device + it.map { it.split(spaces) } + .drop(1) + .filter { it.size >= 4 && (iface == null || it.getOrNull(5) == iface) && + mac.matcher(it[3]).matches() } + .associateBy({ it[3] }, { it[0] }) + } +} diff --git a/mobile/src/main/res/xml/pref_settings.xml b/mobile/src/main/res/xml/pref_settings.xml index b677a495..6e706d11 100644 --- a/mobile/src/main/res/xml/pref_settings.xml +++ b/mobile/src/main/res/xml/pref_settings.xml @@ -8,13 +8,6 @@ android:title="Upstream interface" android:summary="%s" android:defaultValue="tun0"/> -