Use reflection instead of parcel magic to get around networkName check
This commit is contained in:
@@ -167,6 +167,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded
|
|||||||
* (since API 26) `Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V,unsupported`
|
* (since API 26) `Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V,unsupported`
|
||||||
* (prior to API 26) `Landroid/net/wifi/WifiManager;->setWifiApEnabled(Landroid/net/wifi/WifiConfiguration;Z)Z`
|
* (prior to API 26) `Landroid/net/wifi/WifiManager;->setWifiApEnabled(Landroid/net/wifi/WifiConfiguration;Z)Z`
|
||||||
* `Landroid/net/wifi/p2p/WifiP2pConfig$Builder;->MAC_ANY_ADDRESS:Landroid/net/MacAddress;,blocked`
|
* `Landroid/net/wifi/p2p/WifiP2pConfig$Builder;->MAC_ANY_ADDRESS:Landroid/net/MacAddress;,blocked`
|
||||||
|
* (since API 29) `Landroid/net/wifi/p2p/WifiP2pConfig$Builder;->mNetworkName:Ljava/lang/String;,blocked`
|
||||||
* `Landroid/net/wifi/p2p/WifiP2pManager;->startWps(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/WpsInfo;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V,max-target-r`
|
* `Landroid/net/wifi/p2p/WifiP2pManager;->startWps(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/WpsInfo;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V,max-target-r`
|
||||||
* (since API 28, prior to API 30) `Landroid/provider/Settings$Global;->SOFT_AP_TIMEOUT_ENABLED:Ljava/lang/String;,lo-prio,max-target-o`
|
* (since API 28, prior to API 30) `Landroid/provider/Settings$Global;->SOFT_AP_TIMEOUT_ENABLED:Ljava/lang/String;,lo-prio,max-target-o`
|
||||||
* (prior to API 30) `Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I,max-target-q`
|
* (prior to API 30) `Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I,max-target-q`
|
||||||
@@ -300,10 +301,7 @@ Nonexported system resources:
|
|||||||
* (since API 30) `@com.android.networkstack.tethering:array/config_tether_wigig_regexs`
|
* (since API 30) `@com.android.networkstack.tethering:array/config_tether_wigig_regexs`
|
||||||
* (since API 30) `@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownTimeoutMilliseconds`
|
* (since API 30) `@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownTimeoutMilliseconds`
|
||||||
|
|
||||||
Other:
|
Other: Activity `com.android.settings/.Settings$TetherSettingsActivity` is assumed to be exported.
|
||||||
|
|
||||||
* (since API 29) `android.net.wifi.p2p.WifiP2pConfig` needs to be parcelized in a very specific order, except for possible extra fields at the end. (used only for safe mode)
|
|
||||||
* Activity `com.android.settings/.Settings$TetherSettingsActivity` is assumed to be exported.
|
|
||||||
|
|
||||||
For `ip rule` priorities, `RULE_PRIORITY_SECURE_VPN` and `RULE_PRIORITY_TETHERING` is assumed to be 12000 and 18000 respectively;
|
For `ip rule` priorities, `RULE_PRIORITY_SECURE_VPN` and `RULE_PRIORITY_TETHERING` is assumed to be 12000 and 18000 respectively;
|
||||||
(prior to API 24) `RULE_PRIORITY_DEFAULT_NETWORK` is assumed to be 22000 (or at least > 18000).
|
(prior to API 24) `RULE_PRIORITY_DEFAULT_NETWORK` is assumed to be 22000 (or at least > 18000).
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import android.os.Looper
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import be.mygod.librootkotlinx.useParcel
|
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||||
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
||||||
@@ -48,10 +47,6 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
private const val KEY_AUTO_SHUTDOWN = "service.repeater.autoShutdown"
|
private const val KEY_AUTO_SHUTDOWN = "service.repeater.autoShutdown"
|
||||||
private const val KEY_SHUTDOWN_TIMEOUT = "service.repeater.shutdownTimeout"
|
private const val KEY_SHUTDOWN_TIMEOUT = "service.repeater.shutdownTimeout"
|
||||||
private const val KEY_DEVICE_ADDRESS = "service.repeater.mac"
|
private const val KEY_DEVICE_ADDRESS = "service.repeater.mac"
|
||||||
/**
|
|
||||||
* Placeholder for bypassing networkName check.
|
|
||||||
*/
|
|
||||||
private const val PLACEHOLDER_NETWORK_NAME = "DIRECT-00-VPNHotspot"
|
|
||||||
|
|
||||||
var persistentSupported = false
|
var persistentSupported = false
|
||||||
|
|
||||||
@@ -65,6 +60,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
val safeModeConfigurable get() = Build.VERSION.SDK_INT >= 29 && hasP2pValidateName
|
val safeModeConfigurable get() = Build.VERSION.SDK_INT >= 29 && hasP2pValidateName
|
||||||
val safeMode get() = Build.VERSION.SDK_INT >= 29 &&
|
val safeMode get() = Build.VERSION.SDK_INT >= 29 &&
|
||||||
(!hasP2pValidateName || app.pref.getBoolean(KEY_SAFE_MODE, true))
|
(!hasP2pValidateName || app.pref.getBoolean(KEY_SAFE_MODE, true))
|
||||||
|
private val mNetworkName by lazy { UnblockCentral.WifiP2pConfig_Builder_mNetworkName }
|
||||||
|
|
||||||
var networkName: String?
|
var networkName: String?
|
||||||
get() = app.pref.getString(KEY_NETWORK_NAME, null)
|
get() = app.pref.getString(KEY_NETWORK_NAME, null)
|
||||||
@@ -372,7 +368,12 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
p2pManager.createGroup(channel, listener)
|
p2pManager.createGroup(channel, listener)
|
||||||
} else @TargetApi(29) {
|
} else @TargetApi(29) {
|
||||||
p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply {
|
p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply {
|
||||||
setNetworkName(PLACEHOLDER_NETWORK_NAME)
|
try {
|
||||||
|
mNetworkName.set(this, networkName) // bypass networkName check
|
||||||
|
} catch (e: ReflectiveOperationException) {
|
||||||
|
Timber.w(e)
|
||||||
|
setNetworkName(networkName)
|
||||||
|
}
|
||||||
setPassphrase(passphrase)
|
setPassphrase(passphrase)
|
||||||
when (val oc = operatingChannel) {
|
when (val oc = operatingChannel) {
|
||||||
0 -> setGroupOperatingBand(when (val band = operatingBand) {
|
0 -> setGroupOperatingBand(when (val band = operatingBand) {
|
||||||
@@ -386,37 +387,9 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setDeviceAddress(deviceAddress?.toPlatform())
|
setDeviceAddress(deviceAddress?.toPlatform())
|
||||||
}.build().run {
|
}.build(), listener)
|
||||||
useParcel { p ->
|
|
||||||
p.writeParcelable(this, 0)
|
|
||||||
val end = p.dataPosition()
|
|
||||||
p.setDataPosition(0)
|
|
||||||
val creator = p.readString()
|
|
||||||
val deviceAddress = p.readString()
|
|
||||||
val wps = p.readParcelable<WpsInfo>(javaClass.classLoader)
|
|
||||||
val long = p.readLong()
|
|
||||||
check(p.readString() == PLACEHOLDER_NETWORK_NAME)
|
|
||||||
check(p.readString() == passphrase)
|
|
||||||
val extrasLength = end - p.dataPosition()
|
|
||||||
check(extrasLength and 3 == 0) // parcel should be padded
|
|
||||||
if (extrasLength != 4) app.logEvent("p2p_config_extras_unexpected_length") {
|
|
||||||
param("length", extrasLength.toLong())
|
|
||||||
}
|
}
|
||||||
val extras = (0 until extrasLength / 4).map { p.readInt() }
|
} catch (e: RuntimeException) {
|
||||||
p.setDataPosition(0)
|
|
||||||
p.writeString(creator)
|
|
||||||
p.writeString(deviceAddress)
|
|
||||||
p.writeParcelable(wps, 0)
|
|
||||||
p.writeLong(long)
|
|
||||||
p.writeString(networkName)
|
|
||||||
p.writeString(passphrase)
|
|
||||||
extras.forEach(p::writeInt)
|
|
||||||
p.setDataPosition(0)
|
|
||||||
p.readParcelable(javaClass.classLoader)
|
|
||||||
}
|
|
||||||
}, listener)
|
|
||||||
}
|
|
||||||
} catch (e: SecurityException) {
|
|
||||||
Timber.w(e)
|
Timber.w(e)
|
||||||
startFailure(e.readableMessage)
|
startFailure(e.readableMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
package be.mygod.vpnhotspot.util
|
package be.mygod.vpnhotspot.util
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.net.wifi.p2p.WifiP2pConfig
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The central object for accessing all the useful blocked APIs. Thanks Google!
|
* The central object for accessing all the useful blocked APIs. Thanks Google!
|
||||||
|
*
|
||||||
|
* Lazy cannot be used directly as it will create inner classes.
|
||||||
*/
|
*/
|
||||||
@SuppressLint("DiscouragedPrivateApi")
|
@SuppressLint("BlockedPrivateApi", "DiscouragedPrivateApi")
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
object UnblockCentral {
|
object UnblockCentral {
|
||||||
/**
|
/**
|
||||||
@@ -27,4 +30,9 @@ object UnblockCentral {
|
|||||||
|
|
||||||
@RequiresApi(31)
|
@RequiresApi(31)
|
||||||
fun getApInstanceIdentifier(clazz: Class<*>) = init.let { clazz.getDeclaredMethod("getApInstanceIdentifier") }
|
fun getApInstanceIdentifier(clazz: Class<*>) = init.let { clazz.getDeclaredMethod("getApInstanceIdentifier") }
|
||||||
|
|
||||||
|
@get:RequiresApi(29)
|
||||||
|
val WifiP2pConfig_Builder_mNetworkName get() = init.let {
|
||||||
|
WifiP2pConfig.Builder::class.java.getDeclaredField("mNetworkName").apply { isAccessible = true }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user