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"/>
-