diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/DefaultNetworkMonitor.kt b/app/src/main/java/io/nekohasekai/sfa/bg/DefaultNetworkMonitor.kt index d6b30cb..9b5c874 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/DefaultNetworkMonitor.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/DefaultNetworkMonitor.kt @@ -61,19 +61,19 @@ object DefaultNetworkMonitor { } if (Bugs.fixAndroidStack) { GlobalScope.launch(Dispatchers.IO) { - listener.updateDefaultInterface(interfaceName, interfaceIndex) + listener.updateDefaultInterface(interfaceName, interfaceIndex, false, false) } } else { - listener.updateDefaultInterface(interfaceName, interfaceIndex) + listener.updateDefaultInterface(interfaceName, interfaceIndex, false, false) } } } else { if (Bugs.fixAndroidStack) { GlobalScope.launch(Dispatchers.IO) { - listener.updateDefaultInterface("", -1) + listener.updateDefaultInterface("", -1, false, false) } } else { - listener.updateDefaultInterface("", -1) + listener.updateDefaultInterface("", -1, false, false) } } } diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/PlatformInterfaceWrapper.kt b/app/src/main/java/io/nekohasekai/sfa/bg/PlatformInterfaceWrapper.kt index c5bf700..a6c6fe0 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/PlatformInterfaceWrapper.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/PlatformInterfaceWrapper.kt @@ -2,10 +2,14 @@ package io.nekohasekai.sfa.bg import android.annotation.SuppressLint import android.content.pm.PackageManager +import android.net.NetworkCapabilities import android.os.Build import android.os.Process +import android.system.OsConstants +import android.util.Log import androidx.annotation.RequiresApi import io.nekohasekai.libbox.InterfaceUpdateListener +import io.nekohasekai.libbox.Libbox import io.nekohasekai.libbox.NetworkInterfaceIterator import io.nekohasekai.libbox.PlatformInterface import io.nekohasekai.libbox.StringIterator @@ -16,7 +20,6 @@ import java.net.Inet6Address import java.net.InetSocketAddress import java.net.InterfaceAddress import java.net.NetworkInterface -import java.util.Enumeration import io.nekohasekai.libbox.NetworkInterface as LibboxNetworkInterface interface PlatformInterfaceWrapper : PlatformInterface { @@ -44,13 +47,19 @@ interface PlatformInterfaceWrapper : PlatformInterface { destinationAddress: String, destinationPort: Int ): Int { - val uid = Application.connectivity.getConnectionOwnerUid( - ipProtocol, - InetSocketAddress(sourceAddress, sourcePort), - InetSocketAddress(destinationAddress, destinationPort) - ) - if (uid == Process.INVALID_UID) error("android: connection owner not found") - return uid + try { + val uid = Application.connectivity.getConnectionOwnerUid( + ipProtocol, + InetSocketAddress(sourceAddress, sourcePort), + InetSocketAddress(destinationAddress, destinationPort) + ) + if (uid == Process.INVALID_UID) error("android: connection owner not found") + return uid + } catch (e: Exception) { + Log.e("PlatformInterface", "getConnectionOwnerUid", e) + e.printStackTrace(System.err) + throw e + } } override fun packageNameByUid(uid: Int): String { @@ -76,10 +85,6 @@ interface PlatformInterfaceWrapper : PlatformInterface { } } - override fun usePlatformDefaultInterfaceMonitor(): Boolean { - return true - } - override fun startDefaultInterfaceMonitor(listener: InterfaceUpdateListener) { DefaultNetworkMonitor.setListener(listener) } @@ -88,12 +93,56 @@ interface PlatformInterfaceWrapper : PlatformInterface { DefaultNetworkMonitor.setListener(null) } - override fun usePlatformInterfaceGetter(): Boolean { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R - } - override fun getInterfaces(): NetworkInterfaceIterator { - return InterfaceArray(NetworkInterface.getNetworkInterfaces()) + val networks = Application.connectivity.allNetworks + val networkInterfaces = NetworkInterface.getNetworkInterfaces().toList() + val interfaces = mutableListOf() + for (network in networks) { + val boxInterface = LibboxNetworkInterface() + val linkProperties = Application.connectivity.getLinkProperties(network) ?: continue + val networkCapabilities = + Application.connectivity.getNetworkCapabilities(network) ?: continue + boxInterface.name = linkProperties.interfaceName + val networkInterface = + networkInterfaces.find { it.name == boxInterface.name } ?: continue + boxInterface.dnsServer = + StringArray(linkProperties.dnsServers.mapNotNull { it.hostAddress }.iterator()) + boxInterface.type = when { + networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> Libbox.InterfaceTypeWIFI + networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> Libbox.InterfaceTypeCellular + networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> Libbox.InterfaceTypeEthernet + else -> Libbox.InterfaceTypeOther + } + boxInterface.index = networkInterface.index + runCatching { + boxInterface.mtu = networkInterface.mtu + }.onFailure { + Log.e( + "PlatformInterface", "failed to get mtu for interface ${boxInterface.name}", it + ) + } + boxInterface.addresses = + StringArray(networkInterface.interfaceAddresses.mapTo(mutableListOf()) { it.toPrefix() } + .iterator()) + var dumpFlags = 0 + if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + dumpFlags = OsConstants.IFF_UP or OsConstants.IFF_RUNNING + } + if (networkInterface.isLoopback) { + dumpFlags = dumpFlags or OsConstants.IFF_LOOPBACK + } + if (networkInterface.isPointToPoint) { + dumpFlags = dumpFlags or OsConstants.IFF_POINTOPOINT + } + if (networkInterface.supportsMulticast()) { + dumpFlags = dumpFlags or OsConstants.IFF_MULTICAST + } + boxInterface.flags = dumpFlags + boxInterface.metered = + !networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + interfaces.add(boxInterface) + } + return InterfaceArray(interfaces.iterator()) } override fun underNetworkExtension(): Boolean { @@ -108,55 +157,29 @@ interface PlatformInterfaceWrapper : PlatformInterface { } override fun readWIFIState(): WIFIState? { - @Suppress("DEPRECATION") - val wifiInfo = Application.wifiManager.connectionInfo ?: return null + @Suppress("DEPRECATION") val wifiInfo = + Application.wifiManager.connectionInfo ?: return null var ssid = wifiInfo.ssid + if (ssid == "") { + return WIFIState("", "") + } if (ssid.startsWith("\"") && ssid.endsWith("\"")) { ssid = ssid.substring(1, ssid.length - 1) } return WIFIState(ssid, wifiInfo.bssid) } - private class InterfaceArray(private val iterator: Enumeration) : + private class InterfaceArray(private val iterator: Iterator) : NetworkInterfaceIterator { override fun hasNext(): Boolean { - return iterator.hasMoreElements() + return iterator.hasNext() } override fun next(): LibboxNetworkInterface { - val element = iterator.nextElement() - return LibboxNetworkInterface().apply { - name = element.name - index = element.index - runCatching { - mtu = element.mtu - } - addresses = - StringArray( - element.interfaceAddresses.mapTo(mutableListOf()) { it.toPrefix() } - .iterator() - ) - runCatching { - flags = element.flags - } - } + return iterator.next() } - private fun InterfaceAddress.toPrefix(): String { - return if (address is Inet6Address) { - "${Inet6Address.getByAddress(address.address).hostAddress}/${networkPrefixLength}" - } else { - "${address.hostAddress}/${networkPrefixLength}" - } - } - - private val NetworkInterface.flags: Int - @SuppressLint("SoonBlockedPrivateApi") - get() { - val getFlagsMethod = NetworkInterface::class.java.getDeclaredMethod("getFlags") - return getFlagsMethod.invoke(this) as Int - } } private class StringArray(private val iterator: Iterator) : StringIterator { @@ -175,4 +198,17 @@ interface PlatformInterfaceWrapper : PlatformInterface { } } + private fun InterfaceAddress.toPrefix(): String { + return if (address is Inet6Address) { + "${Inet6Address.getByAddress(address.address).hostAddress}/${networkPrefixLength}" + } else { + "${address.hostAddress}/${networkPrefixLength}" + } + } + + private val NetworkInterface.flags: Int + @SuppressLint("SoonBlockedPrivateApi") get() { + val getFlagsMethod = NetworkInterface::class.java.getDeclaredMethod("getFlags") + return getFlagsMethod.invoke(this) as Int + } } \ No newline at end of file