Implement MAC lookup (#68)
* Implement MAC lookup * Refine error processing * Use long to store MAC consistently * Link back to macvendors.co * Undo some havoc * Do not show mac spans for TV * Show MAC and IP in a consistent order * Add IP spans by ipinfo.io * Add SpanFormatter * Fix IPv6 ipinfo.io link * Refine SpanFormatter * Fix pressing the link
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package be.mygod.vpnhotspot.net
|
||||
|
||||
import be.mygod.vpnhotspot.room.macToLong
|
||||
import be.mygod.vpnhotspot.util.parseNumericAddress
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
@@ -8,7 +9,7 @@ import java.net.InetAddress
|
||||
import java.net.NetworkInterface
|
||||
import java.net.SocketException
|
||||
|
||||
data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String, val state: State) {
|
||||
data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: Long, val state: State) {
|
||||
enum class State {
|
||||
INCOMPLETE, VALID, FAILED, DELETING
|
||||
}
|
||||
@@ -50,13 +51,13 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String,
|
||||
"NOARP" -> return emptyList() // skip
|
||||
else -> throw IllegalArgumentException("Unknown state encountered: ${match.groupValues[7]}")
|
||||
}
|
||||
val result = IpNeighbour(ip, dev, lladdr, state)
|
||||
val result = IpNeighbour(ip, dev, lladdr.macToLong(), state)
|
||||
val devParser = devFallback.matchEntire(dev)
|
||||
if (devParser != null) try {
|
||||
val index = devParser.groupValues[1].toInt()
|
||||
val iface = NetworkInterface.getByIndex(index)
|
||||
if (iface == null) Timber.w("Failed to find network interface #$index")
|
||||
else return listOf(IpNeighbour(ip, iface.name, lladdr, state), result)
|
||||
else return listOf(IpNeighbour(ip, iface.name, lladdr.macToLong(), state), result)
|
||||
} catch (_: SocketException) { }
|
||||
listOf(result)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -8,10 +8,10 @@ import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
|
||||
import be.mygod.vpnhotspot.net.monitor.TrafficRecorder
|
||||
import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor
|
||||
import be.mygod.vpnhotspot.room.AppDatabase
|
||||
import be.mygod.vpnhotspot.room.macToLong
|
||||
import be.mygod.vpnhotspot.util.RootSession
|
||||
import be.mygod.vpnhotspot.util.computeIfAbsentCompat
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import java.net.*
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
@@ -146,7 +146,7 @@ class Routing(val downstream: String, ownerAddress: InterfaceAddress? = null) :
|
||||
}
|
||||
private val upstream = Upstream(RULE_PRIORITY_UPSTREAM)
|
||||
|
||||
private inner class Client(private val ip: Inet4Address, mac: String) : AutoCloseable {
|
||||
private inner class Client(private val ip: Inet4Address, mac: Long) : AutoCloseable {
|
||||
private val transaction = RootSession.beginTransaction().safeguard {
|
||||
val address = ip.hostAddress
|
||||
iptablesInsert("vpnhotspot_fwd -i $downstream -s $address -j ACCEPT")
|
||||
@@ -172,7 +172,8 @@ class Routing(val downstream: String, ownerAddress: InterfaceAddress? = null) :
|
||||
val toRemove = HashSet(clients.keys)
|
||||
for (neighbour in neighbours) {
|
||||
if (neighbour.dev != downstream || neighbour.ip !is Inet4Address ||
|
||||
AppDatabase.instance.clientRecordDao.lookup(neighbour.lladdr.macToLong())?.blocked == true) continue
|
||||
runBlocking { AppDatabase.instance.clientRecordDao.lookup(neighbour.lladdr) }
|
||||
?.blocked == true) continue
|
||||
toRemove.remove(neighbour.ip)
|
||||
try {
|
||||
clients.computeIfAbsentCompat(neighbour.ip) { Client(neighbour.ip, neighbour.lladdr) }
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package be.mygod.vpnhotspot.net.monitor
|
||||
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.net.IpNeighbour
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.InetAddress
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -61,7 +63,7 @@ class IpNeighbourMonitor private constructor() : IpMonitor() {
|
||||
|
||||
private fun postUpdateLocked() {
|
||||
if (updatePosted || instance != this) return
|
||||
app.handler.post {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
val neighbours = synchronized(neighbours) {
|
||||
updatePosted = false
|
||||
neighbours.values.toList()
|
||||
|
||||
@@ -6,7 +6,6 @@ import be.mygod.vpnhotspot.DebugHelper
|
||||
import be.mygod.vpnhotspot.net.Routing.Companion.IPTABLES
|
||||
import be.mygod.vpnhotspot.room.AppDatabase
|
||||
import be.mygod.vpnhotspot.room.TrafficRecord
|
||||
import be.mygod.vpnhotspot.room.macToLong
|
||||
import be.mygod.vpnhotspot.util.Event2
|
||||
import be.mygod.vpnhotspot.util.RootSession
|
||||
import be.mygod.vpnhotspot.util.parseNumericAddress
|
||||
@@ -24,11 +23,8 @@ object TrafficRecorder {
|
||||
private val records = HashMap<Pair<InetAddress, String>, TrafficRecord>()
|
||||
val foregroundListeners = Event2<Collection<TrafficRecord>, LongSparseArray<TrafficRecord>>()
|
||||
|
||||
fun register(ip: InetAddress, downstream: String, mac: String) {
|
||||
val record = TrafficRecord(
|
||||
mac = mac.macToLong(),
|
||||
ip = ip,
|
||||
downstream = downstream)
|
||||
fun register(ip: InetAddress, downstream: String, mac: Long) {
|
||||
val record = TrafficRecord(mac = mac, ip = ip, downstream = downstream)
|
||||
AppDatabase.instance.trafficRecordDao.insert(record)
|
||||
synchronized(this) {
|
||||
DebugHelper.log(TAG, "Registering $ip%$downstream")
|
||||
|
||||
Reference in New Issue
Block a user