diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/ArpCache.kt b/mobile/src/main/java/be/mygod/vpnhotspot/ArpCache.kt new file mode 100644 index 00000000..238dea61 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/ArpCache.kt @@ -0,0 +1,20 @@ +package be.mygod.vpnhotspot + +import java.io.File + +class ArpCache(downstream: String) : HashMap() { + 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 >= 6 && parts[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 2fec94f6..f5f70dfa 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt @@ -13,6 +13,7 @@ import android.support.v4.app.NotificationCompat import android.support.v4.content.ContextCompat import android.util.Log import android.widget.Toast +import java.net.InetAddress class HotspotService : Service(), WifiP2pManager.ChannelListener { companion object { @@ -46,7 +47,9 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { private lateinit var p2pManager: WifiP2pManager private lateinit var channel: WifiP2pManager.Channel lateinit var group: WifiP2pGroup - lateinit var clients: MutableCollection + private set + var hostAddress: InetAddress? = null + private set private val binder = HotspotBinder() private var receiverRegistered = false private val receiver: BroadcastReceiver = object : BroadcastReceiver() { @@ -55,14 +58,11 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> if (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0) == WifiP2pManager.WIFI_P2P_STATE_DISABLED) clean() // group may be enabled by other apps - WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION ->{ - clients = intent.getParcelableExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST).deviceList - binder.data?.onClientsChanged() - } WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> { 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) + hostAddress = info.groupOwnerAddress val downstream = group.`interface` if (net.isConnected && downstream != null && this@HotspotService.downstream == null) { this@HotspotService.downstream = downstream @@ -80,7 +80,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { doStart(group) } else startFailure("Something went wrong, please check logcat.") } - group.`interface` binder.data?.onGroupChanged() Log.d(TAG, "${intent.action}: $info, $net, $group") } @@ -93,7 +92,8 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { } // TODO: do something to these hardcoded strings - private var downstream: String? = null + var downstream: String? = null + private set private val upstream = "tun0" private val route = "192.168.49.0/24" private val dns = "8.8.8.8:53" @@ -122,7 +122,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { if (!receiverRegistered) { registerReceiver(receiver, createIntentFilter( WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, - WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION, WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION, WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) receiverRegistered = true @@ -157,7 +156,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { }) private fun doStart(group: WifiP2pGroup) { this.group = group - clients = group.clientList status = Status.ACTIVE startForeground(1, NotificationCompat.Builder(this@HotspotService, CHANNEL) .setWhen(0) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt index 8d396909..e54f9558 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt @@ -47,31 +47,31 @@ class MainActivity : AppCompatActivity(), ServiceConnection { val running get() = binder?.status == HotspotService.Status.ACTIVE val ssid: String @Bindable get() = if (running) binder!!.service.group.networkName else "" val password: String @Bindable get() = if (running) binder!!.service.group.passphrase else "" - val clients @Bindable get() = if (running) binder!!.service.clients else null fun onStatusChanged() { notifyPropertyChanged(BR.switchEnabled) notifyPropertyChanged(BR.serviceStarted) onGroupChanged() - onClientsChanged() } fun onGroupChanged() { notifyPropertyChanged(BR.ssid) notifyPropertyChanged(BR.password) + adapter.fetchClients() } - fun onClientsChanged() = adapter.fetchClients() } class ClientViewHolder(val binding: ClientBinding) : RecyclerView.ViewHolder(binding.root) inner class ClientAdapter : RecyclerView.Adapter() { private var owner: WifiP2pDevice? = null private lateinit var clients: MutableCollection + private lateinit var arpCache: ArpCache fun fetchClients() { val binder = binder!! if (data.running) { owner = binder.service.group.owner - clients = binder.service.clients + clients = binder.service.group.clientList + arpCache = ArpCache(binder.service.downstream!!) } else owner = null notifyDataSetChanged() // recreate everything } @@ -80,10 +80,15 @@ class MainActivity : AppCompatActivity(), ServiceConnection { ClientViewHolder(ClientBinding.inflate(LayoutInflater.from(parent.context))) override fun onBindViewHolder(holder: ClientViewHolder, position: Int) { - holder.binding.device = when (position) { + val device = when (position) { 0 -> owner else -> clients.elementAt(position - 1) } + holder.binding.device = device + holder.binding.ipAddress = when (position) { + 0 -> binder?.service?.hostAddress?.hostAddress?.toString() + else -> arpCache[device?.deviceAddress] + } holder.binding.executePendingBindings() } diff --git a/mobile/src/main/res/layout/client.xml b/mobile/src/main/res/layout/client.xml index fe85c2f8..44dd7204 100644 --- a/mobile/src/main/res/layout/client.xml +++ b/mobile/src/main/res/layout/client.xml @@ -3,44 +3,31 @@ xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"> + + - - - - - - + android:visibility="@{ipAddress == null ? View.GONE : View.VISIBLE}" + android:text="@{ipAddress}" + tools:text="192.168.49.123"/>